Index: /trunk/sources/HeuristicLab 3.2.sln
===================================================================
--- /trunk/sources/HeuristicLab 3.2.sln	(revision 2644)
+++ /trunk/sources/HeuristicLab 3.2.sln	(revision 2645)
@@ -227,6 +227,4 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.SimOpt-3.2", "HeuristicLab.SimOpt\3.2\HeuristicLab.SimOpt-3.2.csproj", "{32DAA44F-944A-465F-A5C9-1C491EE4976D}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.SQLite-3.2", "HeuristicLab.SQLite\3.2\HeuristicLab.SQLite-3.2.csproj", "{6960CBCD-E44B-49B0-BA86-671091C42C36}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.StatisticalAnalysis-3.2", "HeuristicLab.StatisticalAnalysis\3.2\HeuristicLab.StatisticalAnalysis-3.2.csproj", "{1DAA4952-8D6B-4D43-A9E5-5466053DA777}"
 EndProject
@@ -249,6 +247,4 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.SupportVectorMachines-3.2", "HeuristicLab.SupportVectorMachines\3.2\HeuristicLab.SupportVectorMachines-3.2.csproj", "{7E18E25A-BCEB-467A-BACC-ABCA73F9D655}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibSVM", "LibSVM\LibSVM.csproj", "{A16F23B5-FB62-499E-A831-26953AA56FE2}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Modeling-3.2", "HeuristicLab.Modeling\3.2\HeuristicLab.Modeling-3.2.csproj", "{80F7FADA-549D-4151-8856-79B620A50DBA}"
 EndProject
@@ -257,6 +253,4 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Grid.HiveBridge-3.2", "HeuristicLab.Grid.HiveBridge\3.2\HeuristicLab.Grid.HiveBridge-3.2.csproj", "{DFAC1BEA-6D9D-477F-AC7B-E64977644DDB}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsUI", "WinFormsUI\WinFormsUI.csproj", "{C75532C4-765B-418E-B09B-46D36B2ABDB1}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.LinearRegression-3.2", "HeuristicLab.LinearRegression\3.2\HeuristicLab.LinearRegression-3.2.csproj", "{B9A64475-D542-47CF-9688-735F6224F055}"
 EndProject
@@ -265,6 +259,4 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Modeling.Database.SQLServerCompact-3.2", "HeuristicLab.Modeling.Database.SQLServerCompact\3.2\HeuristicLab.Modeling.Database.SQLServerCompact-3.2.csproj", "{EC1AA756-D612-4FA6-AA52-25CF4F8E3836}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.SQLServerCompact-3.2", "HeuristicLab.SQLServerCompact\3.2\HeuristicLab.SQLServerCompact-3.2.csproj", "{31DD6385-7276-49ED-9533-823D4CDF3D2A}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.GP.Interfaces-3.3", "HeuristicLab.GP.Interfaces\3.3\HeuristicLab.GP.Interfaces-3.3.csproj", "{924B6BEA-9A99-40FE-9334-5C01E8D540EC}"
 EndProject
@@ -283,6 +275,4 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.BackgroundProcessing-3.2", "HeuristicLab.BackgroundProcessing\3.2\HeuristicLab.BackgroundProcessing-3.2.csproj", "{589BECAE-69B0-4EB1-8C06-C073531762B7}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ALGLIB", "ALGLIB\ALGLIB.csproj", "{44456535-5DB5-454A-BE2B-7426DA6700B6}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.GP.Tests", "HeuristicLab.GP.Tests\HeuristicLab.GP.Tests.csproj", "{6EDEE199-61FC-48E1-AEDA-AF1C2E722063}"
 EndProject
@@ -294,4 +284,36 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.GP.StructureIdentification.Networks-3.2", "HeuristicLab.GP.StructureIdentification.Networks\3.2\HeuristicLab.GP.StructureIdentification.Networks-3.2.csproj", "{5DBC2F13-EC32-4DCA-9D5F-E60B5EA8459A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.ExtLibs", "HeuristicLab.ExtLibs", "{A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.WinFormsUI", "HeuristicLab.WinFormsUI", "{D04A93C2-6903-4DCA-8803-2EBF60975E47}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.SQLServerCompact-3.5", "HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\HeuristicLab.SQLServerCompact-3.5.csproj", "{31DD6385-7276-49ED-9533-823D4CDF3D2A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.WinFormsUI-2.3.1", "HeuristicLab.WinFormsUI-2.3.1", "{DD1A12A4-88DE-4991-8CBC-9AC2E57EADC3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.WinFormsUI-2.3.1", "HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\HeuristicLab.WinFormsUI-2.3.1\HeuristicLab.WinFormsUI-2.3.1.csproj", "{678E2145-8152-4E19-9646-07D439D00301}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsUI-2.3.1", "HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\WinFormsUI-2.3.1\WinFormsUI-2.3.1.csproj", "{C75532C4-765B-418E-B09B-46D36B2ABDB1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.ALGLIB", "HeuristicLab.ALGLIB", "{BC9B1349-F788-4293-AA27-0B3474761C7F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.ALGLIB-2.1.2.2591", "HeuristicLab.ALGLIB-2.1.2.2591", "{6982D0CF-65DB-49E7-A4FD-7135BCC25A15}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.ALGLIB-2.1.2.2591", "HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\HeuristicLab.ALGLIB-2.1.2.2591\HeuristicLab.ALGLIB-2.1.2.2591.csproj", "{B6C53341-86C0-4063-87E2-F573EFE51132}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ALGLIB-2.1.2.2591", "HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\ALGLIB-2.1.2.2591\ALGLIB-2.1.2.2591.csproj", "{44456535-5DB5-454A-BE2B-7426DA6700B6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.SQLite-1.0.65.0", "HeuristicLab.ExtLibs\HeuristicLab.SQLite\1.0.65.0\HeuristicLab.SQLite-1.0.65.0.csproj", "{6960CBCD-E44B-49B0-BA86-671091C42C36}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.LibSVM", "HeuristicLab.LibSVM", "{66A6D1DA-E53C-455D-9F53-07C0128CBF29}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HeuristicLab.LibSVM-1.6.3", "HeuristicLab.LibSVM-1.6.3", "{FDB65084-1E00-4BCF-90A7-C69BBEC014F8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibSVM-1.6.3", "HeuristicLab.ExtLibs\HeuristicLab.LibSVM\1.6.3\LibSVM-1.6.3\LibSVM-1.6.3.csproj", "{A16F23B5-FB62-499E-A831-26953AA56FE2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.LibSVM-1.6.3", "HeuristicLab.ExtLibs\HeuristicLab.LibSVM\1.6.3\HeuristicLab.LibSVM-1.6.3\HeuristicLab.LibSVM-1.6.3.csproj", "{89B50302-9CEE-4D13-9779-633EADCAE624}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.log4net-1.2.10.0", "HeuristicLab.ExtLibs\HeuristicLab.log4net\1.2.10.0\HeuristicLab.log4net-1.2.10.0.csproj", "{1B3063DB-D71C-4A6A-A359-883E8F53A140}"
 EndProject
 Global
@@ -1778,28 +1800,4 @@
 		{32DAA44F-944A-465F-A5C9-1C491EE4976D}.Release|x86.ActiveCfg = Release|x86
 		{32DAA44F-944A-465F-A5C9-1C491EE4976D}.Release|x86.Build.0 = Release|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x64.ActiveCfg = Debug|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x64.Build.0 = Debug|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x86.ActiveCfg = Debug|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x86.Build.0 = Debug|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x64.ActiveCfg = Debug|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x64.Build.0 = Debug|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x86.ActiveCfg = Debug|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x86.Build.0 = Debug|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x64.ActiveCfg = Debug|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x64.Build.0 = Debug|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x86.ActiveCfg = Debug|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x86.Build.0 = Debug|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x64.ActiveCfg = Release|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x64.Build.0 = Release|x64
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x86.ActiveCfg = Release|x86
-		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x86.Build.0 = Release|x86
 		{1DAA4952-8D6B-4D43-A9E5-5466053DA777}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{1DAA4952-8D6B-4D43-A9E5-5466053DA777}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -2042,28 +2040,4 @@
 		{7E18E25A-BCEB-467A-BACC-ABCA73F9D655}.Release|x86.ActiveCfg = Release|x86
 		{7E18E25A-BCEB-467A-BACC-ABCA73F9D655}.Release|x86.Build.0 = Release|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x64.ActiveCfg = Debug|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x64.Build.0 = Debug|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x86.ActiveCfg = Debug|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x86.Build.0 = Debug|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x64.ActiveCfg = Debug|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x64.Build.0 = Debug|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x86.ActiveCfg = Debug|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x86.Build.0 = Debug|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x64.ActiveCfg = Debug|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x64.Build.0 = Debug|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x86.ActiveCfg = Debug|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x86.Build.0 = Debug|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x64.ActiveCfg = Release|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x64.Build.0 = Release|x64
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x86.ActiveCfg = Release|x86
-		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x86.Build.0 = Release|x86
 		{80F7FADA-549D-4151-8856-79B620A50DBA}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{80F7FADA-549D-4151-8856-79B620A50DBA}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -2138,28 +2112,4 @@
 		{DFAC1BEA-6D9D-477F-AC7B-E64977644DDB}.Release|x86.ActiveCfg = Release|x86
 		{DFAC1BEA-6D9D-477F-AC7B-E64977644DDB}.Release|x86.Build.0 = Release|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x64.ActiveCfg = Debug|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x64.Build.0 = Debug|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x86.ActiveCfg = Debug|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x86.Build.0 = Debug|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x64.ActiveCfg = Debug|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x64.Build.0 = Debug|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x86.ActiveCfg = Debug|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x86.Build.0 = Debug|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x64.ActiveCfg = Debug|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x64.Build.0 = Debug|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x86.ActiveCfg = Debug|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x86.Build.0 = Debug|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x64.ActiveCfg = Release|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x64.Build.0 = Release|x64
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x86.ActiveCfg = Release|x86
-		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x86.Build.0 = Release|x86
 		{B9A64475-D542-47CF-9688-735F6224F055}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{B9A64475-D542-47CF-9688-735F6224F055}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -2234,28 +2184,4 @@
 		{EC1AA756-D612-4FA6-AA52-25CF4F8E3836}.Release|x86.ActiveCfg = Release|x86
 		{EC1AA756-D612-4FA6-AA52-25CF4F8E3836}.Release|x86.Build.0 = Release|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x64.ActiveCfg = Debug|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x64.Build.0 = Debug|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x86.ActiveCfg = Debug|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x86.Build.0 = Debug|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x64.ActiveCfg = Debug|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x64.Build.0 = Debug|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x86.ActiveCfg = Debug|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x86.Build.0 = Debug|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x64.ActiveCfg = Debug|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x64.Build.0 = Debug|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x86.ActiveCfg = Debug|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x86.Build.0 = Debug|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x64.ActiveCfg = Release|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x64.Build.0 = Release|x64
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x86.ActiveCfg = Release|x86
-		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x86.Build.0 = Release|x86
 		{924B6BEA-9A99-40FE-9334-5C01E8D540EC}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{924B6BEA-9A99-40FE-9334-5C01E8D540EC}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -2450,28 +2376,4 @@
 		{589BECAE-69B0-4EB1-8C06-C073531762B7}.Release|x86.ActiveCfg = Release|x86
 		{589BECAE-69B0-4EB1-8C06-C073531762B7}.Release|x86.Build.0 = Release|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x64.ActiveCfg = Debug|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x64.Build.0 = Debug|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x86.ActiveCfg = Debug|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x86.Build.0 = Debug|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x64.ActiveCfg = Debug|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x64.Build.0 = Debug|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x86.ActiveCfg = Debug|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x86.Build.0 = Debug|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x64.ActiveCfg = Debug|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x64.Build.0 = Debug|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x86.ActiveCfg = Debug|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x86.Build.0 = Debug|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|Any CPU.Build.0 = Release|Any CPU
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x64.ActiveCfg = Release|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x64.Build.0 = Release|x64
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x86.ActiveCfg = Release|x86
-		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x86.Build.0 = Release|x86
 		{6EDEE199-61FC-48E1-AEDA-AF1C2E722063}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{6EDEE199-61FC-48E1-AEDA-AF1C2E722063}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -2590,7 +2492,228 @@
 		{5DBC2F13-EC32-4DCA-9D5F-E60B5EA8459A}.Release|x86.ActiveCfg = Release|x86
 		{5DBC2F13-EC32-4DCA-9D5F-E60B5EA8459A}.Release|x86.Build.0 = Release|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x64.ActiveCfg = Debug|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x64.Build.0 = Debug|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x86.ActiveCfg = Debug|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.CEDMA Debug|x86.Build.0 = Debug|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x64.ActiveCfg = Debug|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x64.Build.0 = Debug|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x86.ActiveCfg = Debug|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Debug|x86.Build.0 = Debug|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x64.ActiveCfg = Debug|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x64.Build.0 = Debug|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x86.ActiveCfg = Debug|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Modeling Debug|x86.Build.0 = Debug|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x64.ActiveCfg = Release|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x64.Build.0 = Release|x64
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x86.ActiveCfg = Release|x86
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A}.Release|x86.Build.0 = Release|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.CEDMA Debug|x64.ActiveCfg = Debug|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.CEDMA Debug|x64.Build.0 = Debug|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.CEDMA Debug|x86.ActiveCfg = Debug|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.CEDMA Debug|x86.Build.0 = Debug|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.Debug|x64.ActiveCfg = Debug|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.Debug|x64.Build.0 = Debug|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.Debug|x86.ActiveCfg = Debug|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.Debug|x86.Build.0 = Debug|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.Modeling Debug|x64.ActiveCfg = Debug|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.Modeling Debug|x64.Build.0 = Debug|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.Modeling Debug|x86.ActiveCfg = Debug|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.Modeling Debug|x86.Build.0 = Debug|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.Release|Any CPU.Build.0 = Release|Any CPU
+		{678E2145-8152-4E19-9646-07D439D00301}.Release|x64.ActiveCfg = Release|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.Release|x64.Build.0 = Release|x64
+		{678E2145-8152-4E19-9646-07D439D00301}.Release|x86.ActiveCfg = Release|x86
+		{678E2145-8152-4E19-9646-07D439D00301}.Release|x86.Build.0 = Release|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x64.ActiveCfg = Debug|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x64.Build.0 = Debug|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x86.ActiveCfg = Debug|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.CEDMA Debug|x86.Build.0 = Debug|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x64.ActiveCfg = Debug|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x64.Build.0 = Debug|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x86.ActiveCfg = Debug|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Debug|x86.Build.0 = Debug|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x64.ActiveCfg = Debug|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x64.Build.0 = Debug|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x86.ActiveCfg = Debug|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Modeling Debug|x86.Build.0 = Debug|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x64.ActiveCfg = Release|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x64.Build.0 = Release|x64
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x86.ActiveCfg = Release|x86
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1}.Release|x86.Build.0 = Release|x86
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.CEDMA Debug|x64.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.CEDMA Debug|x86.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Debug|x64.ActiveCfg = Debug|x64
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Debug|x64.Build.0 = Debug|x64
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Debug|x86.ActiveCfg = Debug|x86
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Debug|x86.Build.0 = Debug|x86
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Modeling Debug|x64.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Modeling Debug|x86.ActiveCfg = Debug|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Release|x64.ActiveCfg = Release|x64
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Release|x64.Build.0 = Release|x64
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Release|x86.ActiveCfg = Release|x86
+		{B6C53341-86C0-4063-87E2-F573EFE51132}.Release|x86.Build.0 = Release|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x64.ActiveCfg = Debug|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x64.Build.0 = Debug|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x86.ActiveCfg = Debug|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.CEDMA Debug|x86.Build.0 = Debug|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x64.ActiveCfg = Debug|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x64.Build.0 = Debug|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x86.ActiveCfg = Debug|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Debug|x86.Build.0 = Debug|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x64.ActiveCfg = Debug|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x64.Build.0 = Debug|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x86.ActiveCfg = Debug|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Modeling Debug|x86.Build.0 = Debug|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x64.ActiveCfg = Release|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x64.Build.0 = Release|x64
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x86.ActiveCfg = Release|x86
+		{44456535-5DB5-454A-BE2B-7426DA6700B6}.Release|x86.Build.0 = Release|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x64.ActiveCfg = Debug|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x64.Build.0 = Debug|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x86.ActiveCfg = Debug|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.CEDMA Debug|x86.Build.0 = Debug|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x64.ActiveCfg = Debug|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x64.Build.0 = Debug|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x86.ActiveCfg = Debug|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Debug|x86.Build.0 = Debug|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x64.ActiveCfg = Debug|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x64.Build.0 = Debug|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x86.ActiveCfg = Debug|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Modeling Debug|x86.Build.0 = Debug|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x64.ActiveCfg = Release|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x64.Build.0 = Release|x64
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x86.ActiveCfg = Release|x86
+		{6960CBCD-E44B-49B0-BA86-671091C42C36}.Release|x86.Build.0 = Release|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x64.ActiveCfg = Debug|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x64.Build.0 = Debug|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x86.ActiveCfg = Debug|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.CEDMA Debug|x86.Build.0 = Debug|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x64.ActiveCfg = Debug|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x64.Build.0 = Debug|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x86.ActiveCfg = Debug|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Debug|x86.Build.0 = Debug|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x64.ActiveCfg = Debug|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x64.Build.0 = Debug|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x86.ActiveCfg = Debug|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Modeling Debug|x86.Build.0 = Debug|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x64.ActiveCfg = Release|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x64.Build.0 = Release|x64
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x86.ActiveCfg = Release|x86
+		{A16F23B5-FB62-499E-A831-26953AA56FE2}.Release|x86.Build.0 = Release|x86
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.CEDMA Debug|x64.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.CEDMA Debug|x86.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Debug|x64.ActiveCfg = Debug|x64
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Debug|x64.Build.0 = Debug|x64
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Debug|x86.ActiveCfg = Debug|x86
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Debug|x86.Build.0 = Debug|x86
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Modeling Debug|x64.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Modeling Debug|x86.ActiveCfg = Debug|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Release|Any CPU.Build.0 = Release|Any CPU
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Release|x64.ActiveCfg = Release|x64
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Release|x64.Build.0 = Release|x64
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Release|x86.ActiveCfg = Release|x86
+		{89B50302-9CEE-4D13-9779-633EADCAE624}.Release|x86.Build.0 = Release|x86
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.CEDMA Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.CEDMA Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.CEDMA Debug|x64.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.CEDMA Debug|x86.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Debug|x64.ActiveCfg = Debug|x64
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Debug|x64.Build.0 = Debug|x64
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Debug|x86.ActiveCfg = Debug|x86
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Debug|x86.Build.0 = Debug|x86
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Modeling Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Modeling Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Modeling Debug|x64.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Modeling Debug|x86.ActiveCfg = Debug|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Release|x64.ActiveCfg = Release|x64
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Release|x64.Build.0 = Release|x64
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Release|x86.ActiveCfg = Release|x86
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{D04A93C2-6903-4DCA-8803-2EBF60975E47} = {A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}
+		{31DD6385-7276-49ED-9533-823D4CDF3D2A} = {A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}
+		{BC9B1349-F788-4293-AA27-0B3474761C7F} = {A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}
+		{6960CBCD-E44B-49B0-BA86-671091C42C36} = {A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}
+		{66A6D1DA-E53C-455D-9F53-07C0128CBF29} = {A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}
+		{1B3063DB-D71C-4A6A-A359-883E8F53A140} = {A0AEB817-CAC7-4DC8-8D39-0E040BA027E5}
+		{DD1A12A4-88DE-4991-8CBC-9AC2E57EADC3} = {D04A93C2-6903-4DCA-8803-2EBF60975E47}
+		{678E2145-8152-4E19-9646-07D439D00301} = {DD1A12A4-88DE-4991-8CBC-9AC2E57EADC3}
+		{C75532C4-765B-418E-B09B-46D36B2ABDB1} = {DD1A12A4-88DE-4991-8CBC-9AC2E57EADC3}
+		{6982D0CF-65DB-49E7-A4FD-7135BCC25A15} = {BC9B1349-F788-4293-AA27-0B3474761C7F}
+		{B6C53341-86C0-4063-87E2-F573EFE51132} = {6982D0CF-65DB-49E7-A4FD-7135BCC25A15}
+		{44456535-5DB5-454A-BE2B-7426DA6700B6} = {6982D0CF-65DB-49E7-A4FD-7135BCC25A15}
+		{FDB65084-1E00-4BCF-90A7-C69BBEC014F8} = {66A6D1DA-E53C-455D-9F53-07C0128CBF29}
+		{A16F23B5-FB62-499E-A831-26953AA56FE2} = {FDB65084-1E00-4BCF-90A7-C69BBEC014F8}
+		{89B50302-9CEE-4D13-9779-633EADCAE624} = {FDB65084-1E00-4BCF-90A7-C69BBEC014F8}
+	EndGlobalSection
 EndGlobal
Index: /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLab.AdvancedOptimizationFrontend-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLab.AdvancedOptimizationFrontend-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLab.AdvancedOptimizationFrontend-3.2.csproj	(revision 2645)
@@ -123,15 +123,11 @@
       <Name>HeuristicLab.Core-3.2</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\HeuristicLab.MainForm.WindowsForms\3.2\HeuristicLab.MainForm.WindowsForms-3.2.csproj">
-      <Project>{D49BBA1A-880B-46BD-82CF-3CF1AAE0B45C}</Project>
-      <Name>HeuristicLab.MainForm.WindowsForms-3.2</Name>
+    <ProjectReference Include="..\..\HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\WinFormsUI-2.3.1\WinFormsUI-2.3.1.csproj">
+      <Project>{C75532C4-765B-418E-B09B-46D36B2ABDB1}</Project>
+      <Name>WinFormsUI-2.3.1</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
       <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
       <Name>HeuristicLab.PluginInfrastructure</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\WinFormsUI\WinFormsUI.csproj">
-      <Project>{C75532C4-765B-418E-B09B-46D36B2ABDB1}</Project>
-      <Name>WinFormsUI</Name>
     </ProjectReference>
   </ItemGroup>
Index: /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLabAdvancedOptimizationFrontendApplication.cs
===================================================================
--- /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLabAdvancedOptimizationFrontendApplication.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLabAdvancedOptimizationFrontendApplication.cs	(revision 2645)
@@ -31,5 +31,5 @@
   /// </summary>
   [Application("HeuristicLab 3.2 (dockable)", "Next generation heuristic optimization environment.")]
-  class HeuristicLabAdvancedOptimizationFrontendApplication : ApplicationBase {
+  public class HeuristicLabAdvancedOptimizationFrontendApplication : ApplicationBase {
     /// <summary>
     /// Runs the application and displays the main window.
Index: /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLabAdvancedOptimizationFrontendPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLabAdvancedOptimizationFrontendPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.AdvancedOptimizationFrontend/3.2/HeuristicLabAdvancedOptimizationFrontendPlugin.cs	(revision 2645)
@@ -33,5 +33,5 @@
   [PluginFile("HeuristicLab.AdvancedOptimizationFrontend-3.2.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Core-3.2")]
-  [PluginDependency("HeuristicLab.MainForm.WindowsForms-3.2")]
+  [PluginDependency("HeuristicLab.WinFormsUI-2.3.1")]
   public class HeuristicLabAdvancedOptimizationFrontendPlugin : PluginBase {
   }
Index: /trunk/sources/HeuristicLab.ArtificialNeuralNetworks/3.2/HeuristicLab.ArtificialNeuralNetworks-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ArtificialNeuralNetworks/3.2/HeuristicLab.ArtificialNeuralNetworks-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.ArtificialNeuralNetworks/3.2/HeuristicLab.ArtificialNeuralNetworks-3.2.csproj	(revision 2645)
@@ -89,8 +89,4 @@
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\ALGLIB\ALGLIB.csproj">
-      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
-      <Name>ALGLIB</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Core\3.2\HeuristicLab.Core-3.2.csproj">
       <Project>{F43B59AB-2B8C-4570-BC1E-15592086517C}</Project>
@@ -104,4 +100,8 @@
       <Project>{F473D9AF-3F09-4296-9F28-3C65118DAFFA}</Project>
       <Name>HeuristicLab.Data-3.2</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\ALGLIB-2.1.2.2591\ALGLIB-2.1.2.2591.csproj">
+      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
+      <Name>ALGLIB-2.1.2.2591</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Modeling\3.2\HeuristicLab.Modeling-3.2.csproj">
Index: /trunk/sources/HeuristicLab.ArtificialNeuralNetworks/3.2/HeuristicLabArtificialNeuralNetworksPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ArtificialNeuralNetworks/3.2/HeuristicLabArtificialNeuralNetworksPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.ArtificialNeuralNetworks/3.2/HeuristicLabArtificialNeuralNetworksPlugin.cs	(revision 2645)
@@ -27,5 +27,5 @@
   [Plugin("HeuristicLab.ArtificialNeuralNetworks-3.2")]
   [PluginFile("HeuristicLab.ArtificialNeuralNetworks-3.2.dll", PluginFileType.Assembly)]
-  [PluginDependency("ALGLIB")]
+  [PluginDependency("HeuristicLab.ALGLIB-2.1.2.2591")]
   [PluginDependency("HeuristicLab.Core-3.2")]
   [PluginDependency("HeuristicLab.Data-3.2")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ALGLIB License.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ALGLIB License.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ALGLIB License.txt	(revision 2645)
@@ -0,0 +1,16 @@
+﻿Copyright (c) 2003-2009 Sergey Bochkanov (ALGLIB project).
+
+>>> LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ALGLIB-2.1.2.2591.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ALGLIB-2.1.2.2591.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ALGLIB-2.1.2.2591.csproj	(revision 2645)
@@ -0,0 +1,220 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{44456535-5DB5-454A-BE2B-7426DA6700B6}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ALGLIB</RootNamespace>
+    <AssemblyName>ALGLIB-2.1.2.2591</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="airyf.cs" />
+    <Compile Include="ap.cs" />
+    <Compile Include="autogk.cs" />
+    <Compile Include="bdss.cs" />
+    <Compile Include="bdsvd.cs" />
+    <Compile Include="bessel.cs" />
+    <Compile Include="betaf.cs" />
+    <Compile Include="bidiagonal.cs" />
+    <Compile Include="binomialdistr.cs" />
+    <Compile Include="blas.cs" />
+    <Compile Include="cblas.cs" />
+    <Compile Include="cdet.cs" />
+    <Compile Include="chebyshev.cs" />
+    <Compile Include="chisquaredistr.cs" />
+    <Compile Include="cholesky.cs" />
+    <Compile Include="cinverse.cs" />
+    <Compile Include="clu.cs" />
+    <Compile Include="conv.cs" />
+    <Compile Include="corr.cs" />
+    <Compile Include="correlation.cs" />
+    <Compile Include="correlationtests.cs" />
+    <Compile Include="cqr.cs" />
+    <Compile Include="crcond.cs" />
+    <Compile Include="creflections.cs" />
+    <Compile Include="csolve.cs" />
+    <Compile Include="ctrinverse.cs" />
+    <Compile Include="ctrlinsolve.cs" />
+    <Compile Include="dawson.cs" />
+    <Compile Include="densesolver.cs" />
+    <Compile Include="descriptivestatistics.cs" />
+    <Compile Include="det.cs" />
+    <Compile Include="dforest.cs" />
+    <Compile Include="elliptic.cs" />
+    <Compile Include="estnorm.cs" />
+    <Compile Include="expintegrals.cs" />
+    <Compile Include="fdistr.cs" />
+    <Compile Include="fft.cs" />
+    <Compile Include="fht.cs" />
+    <Compile Include="fresnel.cs" />
+    <Compile Include="ftbase.cs" />
+    <Compile Include="gammafunc.cs" />
+    <Compile Include="gkq.cs" />
+    <Compile Include="gq.cs" />
+    <Compile Include="hbisinv.cs" />
+    <Compile Include="hblas.cs" />
+    <Compile Include="hcholesky.cs" />
+    <Compile Include="hermite.cs" />
+    <Compile Include="hessenberg.cs" />
+    <Compile Include="hevd.cs" />
+    <Compile Include="hqrnd.cs" />
+    <Compile Include="hsschur.cs" />
+    <Compile Include="htridiagonal.cs" />
+    <Compile Include="ibetaf.cs" />
+    <Compile Include="igammaf.cs" />
+    <Compile Include="inv.cs" />
+    <Compile Include="inverseupdate.cs" />
+    <Compile Include="jacobianelliptic.cs" />
+    <Compile Include="jarquebera.cs" />
+    <Compile Include="kmeans.cs" />
+    <Compile Include="laguerre.cs" />
+    <Compile Include="lbfgs.cs" />
+    <Compile Include="lda.cs" />
+    <Compile Include="ldlt.cs" />
+    <Compile Include="leastsquares.cs" />
+    <Compile Include="legendre.cs" />
+    <Compile Include="linreg.cs" />
+    <Compile Include="logit.cs" />
+    <Compile Include="lq.cs" />
+    <Compile Include="lsfit.cs" />
+    <Compile Include="lu.cs" />
+    <Compile Include="mannwhitneyu.cs" />
+    <Compile Include="matgen.cs" />
+    <Compile Include="minlm.cs" />
+    <Compile Include="mlpbase.cs" />
+    <Compile Include="mlpe.cs" />
+    <Compile Include="mlptrain.cs" />
+    <Compile Include="nearunityunit.cs" />
+    <Compile Include="normaldistr.cs" />
+    <Compile Include="nsevd.cs" />
+    <Compile Include="odesolver.cs" />
+    <Compile Include="pca.cs" />
+    <Compile Include="poissondistr.cs" />
+    <Compile Include="polint.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="psif.cs" />
+    <Compile Include="qr.cs" />
+    <Compile Include="ratint.cs" />
+    <Compile Include="ratinterpolation.cs" />
+    <Compile Include="rcond.cs" />
+    <Compile Include="reflections.cs" />
+    <Compile Include="rotations.cs" />
+    <Compile Include="sbisinv.cs" />
+    <Compile Include="sblas.cs" />
+    <Compile Include="schur.cs" />
+    <Compile Include="sdet.cs" />
+    <Compile Include="sevd.cs" />
+    <Compile Include="sinverse.cs" />
+    <Compile Include="spddet.cs" />
+    <Compile Include="spdgevd.cs" />
+    <Compile Include="spdinverse.cs" />
+    <Compile Include="spdrcond.cs" />
+    <Compile Include="spdsolve.cs" />
+    <Compile Include="spline1d.cs" />
+    <Compile Include="spline2d.cs" />
+    <Compile Include="spline3.cs" />
+    <Compile Include="srcond.cs" />
+    <Compile Include="ssolve.cs" />
+    <Compile Include="stest.cs" />
+    <Compile Include="studenttdistr.cs" />
+    <Compile Include="studentttests.cs" />
+    <Compile Include="svd.cs" />
+    <Compile Include="taskgen.cs" />
+    <Compile Include="tdbisinv.cs" />
+    <Compile Include="tdevd.cs" />
+    <Compile Include="tridiagonal.cs" />
+    <Compile Include="trigintegrals.cs" />
+    <Compile Include="trinverse.cs" />
+    <Compile Include="trlinsolve.cs" />
+    <Compile Include="tsort.cs" />
+    <Compile Include="variancetests.cs" />
+    <Compile Include="wsr.cs" />
+    <Compile Include="xblas.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>
+    </PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/AlglibPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/AlglibPlugin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/AlglibPlugin.cs	(revision 2645)
@@ -0,0 +1,34 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2009 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.PluginInfrastructure;
+
+namespace ALGLIB {
+  [Plugin("ALGLIB")]
+  [PluginFile("ALGLIB.dll", PluginFileType.Assembly)]
+  [PluginFile("ALGLIB License.txt", PluginFileType.License)]
+  public class AlgLibPlugin : PluginBase {
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/Properties/AssemblyInfo.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/Properties/AssemblyInfo.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/Properties/AssemblyInfo.cs	(revision 2645)
@@ -0,0 +1,57 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ALGLIB")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ALGLIB")]
+[assembly: AssemblyCopyright("Copyright (c) 2003-2009 Sergey Bochkanov (ALGLIB project)")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9e8c630f-f39d-42ae-97fd-2184b680db31")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("2.1.2.2591")]
+[assembly: AssemblyFileVersion("2.1.2.2591")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/airyf.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/airyf.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/airyf.cs	(revision 2645)
@@ -0,0 +1,366 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class airyf
+    {
+        /*************************************************************************
+        Airy function
+
+        Solution of the differential equation
+
+        y"(x) = xy.
+
+        The function returns the two independent solutions Ai, Bi
+        and their first derivatives Ai'(x), Bi'(x).
+
+        Evaluation is by power series summation for small x,
+        by rational minimax approximations for large x.
+
+
+
+        ACCURACY:
+        Error criterion is absolute when function <= 1, relative
+        when function > 1, except * denotes relative error criterion.
+        For large negative x, the absolute error increases as x^1.5.
+        For large positive x, the relative error increases as x^1.5.
+
+        Arithmetic  domain   function  # trials      peak         rms
+        IEEE        -10, 0     Ai        10000       1.6e-15     2.7e-16
+        IEEE          0, 10    Ai        10000       2.3e-14*    1.8e-15*
+        IEEE        -10, 0     Ai'       10000       4.6e-15     7.6e-16
+        IEEE          0, 10    Ai'       10000       1.8e-14*    1.5e-15*
+        IEEE        -10, 10    Bi        30000       4.2e-15     5.3e-16
+        IEEE        -10, 10    Bi'       30000       4.9e-15     7.3e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static void airy(double x,
+            ref double ai,
+            ref double aip,
+            ref double bi,
+            ref double bip)
+        {
+            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;
+
+            sqpii = 5.64189583547756286948E-1;
+            c1 = 0.35502805388781723926;
+            c2 = 0.258819403792806798405;
+            sqrt3 = 1.732050807568877293527;
+            domflg = 0;
+            if( (double)(x)>(double)(25.77) )
+            {
+                ai = 0;
+                aip = 0;
+                bi = AP.Math.MaxRealNumber;
+                bip = AP.Math.MaxRealNumber;
+                return;
+            }
+            if( (double)(x)<(double)(-2.09) )
+            {
+                domflg = 15;
+                t = Math.Sqrt(-x);
+                zeta = -(2.0*x*t/3.0);
+                t = Math.Sqrt(t);
+                k = sqpii/t;
+                z = 1.0/zeta;
+                zz = z*z;
+                afn = -1.31696323418331795333E-1;
+                afn = afn*zz-6.26456544431912369773E-1;
+                afn = afn*zz-6.93158036036933542233E-1;
+                afn = afn*zz-2.79779981545119124951E-1;
+                afn = afn*zz-4.91900132609500318020E-2;
+                afn = afn*zz-4.06265923594885404393E-3;
+                afn = afn*zz-1.59276496239262096340E-4;
+                afn = afn*zz-2.77649108155232920844E-6;
+                afn = afn*zz-1.67787698489114633780E-8;
+                afd = 1.00000000000000000000E0;
+                afd = afd*zz+1.33560420706553243746E1;
+                afd = afd*zz+3.26825032795224613948E1;
+                afd = afd*zz+2.67367040941499554804E1;
+                afd = afd*zz+9.18707402907259625840E0;
+                afd = afd*zz+1.47529146771666414581E0;
+                afd = afd*zz+1.15687173795188044134E-1;
+                afd = afd*zz+4.40291641615211203805E-3;
+                afd = afd*zz+7.54720348287414296618E-5;
+                afd = afd*zz+4.51850092970580378464E-7;
+                uf = 1.0+zz*afn/afd;
+                agn = 1.97339932091685679179E-2;
+                agn = agn*zz+3.91103029615688277255E-1;
+                agn = agn*zz+1.06579897599595591108E0;
+                agn = agn*zz+9.39169229816650230044E-1;
+                agn = agn*zz+3.51465656105547619242E-1;
+                agn = agn*zz+6.33888919628925490927E-2;
+                agn = agn*zz+5.85804113048388458567E-3;
+                agn = agn*zz+2.82851600836737019778E-4;
+                agn = agn*zz+6.98793669997260967291E-6;
+                agn = agn*zz+8.11789239554389293311E-8;
+                agn = agn*zz+3.41551784765923618484E-10;
+                agd = 1.00000000000000000000E0;
+                agd = agd*zz+9.30892908077441974853E0;
+                agd = agd*zz+1.98352928718312140417E1;
+                agd = agd*zz+1.55646628932864612953E1;
+                agd = agd*zz+5.47686069422975497931E0;
+                agd = agd*zz+9.54293611618961883998E-1;
+                agd = agd*zz+8.64580826352392193095E-2;
+                agd = agd*zz+4.12656523824222607191E-3;
+                agd = agd*zz+1.01259085116509135510E-4;
+                agd = agd*zz+1.17166733214413521882E-6;
+                agd = agd*zz+4.91834570062930015649E-9;
+                ug = z*agn/agd;
+                theta = zeta+0.25*Math.PI;
+                f = Math.Sin(theta);
+                g = Math.Cos(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;
+                apfd = 1.00000000000000000000E0;
+                apfd = apfd*zz+1.47345854687502542552E1;
+                apfd = apfd*zz+3.75423933435489594466E1;
+                apfd = apfd*zz+3.14657751203046424330E1;
+                apfd = apfd*zz+1.09969125207298778536E1;
+                apfd = apfd*zz+1.78885054766999417817E0;
+                apfd = apfd*zz+1.41733275753662636873E-1;
+                apfd = apfd*zz+5.44066067017226003627E-3;
+                apfd = apfd*zz+9.39421290654511171663E-5;
+                apfd = apfd*zz+5.65978713036027009243E-7;
+                uf = 1.0+zz*apfn/apfd;
+                apgn = -3.55615429033082288335E-2;
+                apgn = apgn*zz-6.37311518129435504426E-1;
+                apgn = apgn*zz-1.70856738884312371053E0;
+                apgn = apgn*zz-1.50221872117316635393E0;
+                apgn = apgn*zz-5.63606665822102676611E-1;
+                apgn = apgn*zz-1.02101031120216891789E-1;
+                apgn = apgn*zz-9.48396695961445269093E-3;
+                apgn = apgn*zz-4.60325307486780994357E-4;
+                apgn = apgn*zz-1.14300836484517375919E-5;
+                apgn = apgn*zz-1.33415518685547420648E-7;
+                apgn = apgn*zz-5.63803833958893494476E-10;
+                apgd = 1.00000000000000000000E0;
+                apgd = apgd*zz+9.85865801696130355144E0;
+                apgd = apgd*zz+2.16401867356585941885E1;
+                apgd = apgd*zz+1.73130776389749389525E1;
+                apgd = apgd*zz+6.17872175280828766327E0;
+                apgd = apgd*zz+1.08848694396321495475E0;
+                apgd = apgd*zz+9.95005543440888479402E-2;
+                apgd = apgd*zz+4.78468199683886610842E-3;
+                apgd = apgd*zz+1.18159633322838625562E-4;
+                apgd = apgd*zz+1.37480673554219441465E-6;
+                apgd = apgd*zz+5.79912514929147598821E-9;
+                ug = z*apgn/apgd;
+                k = sqpii*t;
+                aip = -(k*(g*uf+f*ug));
+                bip = k*(f*uf-g*ug);
+                return;
+            }
+            if( (double)(x)>=(double)(2.09) )
+            {
+                domflg = 5;
+                t = Math.Sqrt(x);
+                zeta = 2.0*x*t/3.0;
+                g = Math.Exp(zeta);
+                t = Math.Sqrt(t);
+                k = 2.0*t*g;
+                z = 1.0/zeta;
+                an = 3.46538101525629032477E-1;
+                an = an*z+1.20075952739645805542E1;
+                an = an*z+7.62796053615234516538E1;
+                an = an*z+1.68089224934630576269E2;
+                an = an*z+1.59756391350164413639E2;
+                an = an*z+7.05360906840444183113E1;
+                an = an*z+1.40264691163389668864E1;
+                an = an*z+9.99999999999999995305E-1;
+                ad = 5.67594532638770212846E-1;
+                ad = ad*z+1.47562562584847203173E1;
+                ad = ad*z+8.45138970141474626562E1;
+                ad = ad*z+1.77318088145400459522E2;
+                ad = ad*z+1.64234692871529701831E2;
+                ad = ad*z+7.14778400825575695274E1;
+                ad = ad*z+1.40959135607834029598E1;
+                ad = ad*z+1.00000000000000000470E0;
+                f = an/ad;
+                ai = sqpii*f/k;
+                k = -(0.5*sqpii*t/g);
+                apn = 6.13759184814035759225E-1;
+                apn = apn*z+1.47454670787755323881E1;
+                apn = apn*z+8.20584123476060982430E1;
+                apn = apn*z+1.71184781360976385540E2;
+                apn = apn*z+1.59317847137141783523E2;
+                apn = apn*z+6.99778599330103016170E1;
+                apn = apn*z+1.39470856980481566958E1;
+                apn = apn*z+1.00000000000000000550E0;
+                apd = 3.34203677749736953049E-1;
+                apd = apd*z+1.11810297306158156705E1;
+                apd = apd*z+7.11727352147859965283E1;
+                apd = apd*z+1.58778084372838313640E2;
+                apd = apd*z+1.53206427475809220834E2;
+                apd = apd*z+6.86752304592780337944E1;
+                apd = apd*z+1.38498634758259442477E1;
+                apd = apd*z+9.99999999999999994502E-1;
+                f = apn/apd;
+                aip = f*k;
+                if( (double)(x)>(double)(8.3203353) )
+                {
+                    bn16 = -2.53240795869364152689E-1;
+                    bn16 = bn16*z+5.75285167332467384228E-1;
+                    bn16 = bn16*z-3.29907036873225371650E-1;
+                    bn16 = bn16*z+6.44404068948199951727E-2;
+                    bn16 = bn16*z-3.82519546641336734394E-3;
+                    bd16 = 1.00000000000000000000E0;
+                    bd16 = bd16*z-7.15685095054035237902E0;
+                    bd16 = bd16*z+1.06039580715664694291E1;
+                    bd16 = bd16*z-5.23246636471251500874E0;
+                    bd16 = bd16*z+9.57395864378383833152E-1;
+                    bd16 = bd16*z-5.50828147163549611107E-2;
+                    f = z*bn16/bd16;
+                    k = sqpii*g;
+                    bi = k*(1.0+f)/t;
+                    bppn = 4.65461162774651610328E-1;
+                    bppn = bppn*z-1.08992173800493920734E0;
+                    bppn = bppn*z+6.38800117371827987759E-1;
+                    bppn = bppn*z-1.26844349553102907034E-1;
+                    bppn = bppn*z+7.62487844342109852105E-3;
+                    bppd = 1.00000000000000000000E0;
+                    bppd = bppd*z-8.70622787633159124240E0;
+                    bppd = bppd*z+1.38993162704553213172E1;
+                    bppd = bppd*z-7.14116144616431159572E0;
+                    bppd = bppd*z+1.34008595960680518666E0;
+                    bppd = bppd*z-7.84273211323341930448E-2;
+                    f = z*bppn/bppd;
+                    bip = k*t*(1.0+f);
+                    return;
+                }
+            }
+            f = 1.0;
+            g = x;
+            t = 1.0;
+            uf = 1.0;
+            ug = x;
+            k = 1.0;
+            z = x*x*x;
+            while( (double)(t)>(double)(AP.Math.MachineEpsilon) )
+            {
+                uf = uf*z;
+                k = k+1.0;
+                uf = uf/k;
+                ug = ug*z;
+                k = k+1.0;
+                ug = ug/k;
+                uf = uf/k;
+                f = f+uf;
+                k = k+1.0;
+                ug = ug/k;
+                g = g+ug;
+                t = Math.Abs(uf/f);
+            }
+            uf = c1*f;
+            ug = c2*g;
+            if( domflg%2==0 )
+            {
+                ai = uf-ug;
+            }
+            if( domflg/2%2==0 )
+            {
+                bi = sqrt3*(uf+ug);
+            }
+            k = 4.0;
+            uf = x*x/2.0;
+            ug = z/3.0;
+            f = uf;
+            g = 1.0+ug;
+            uf = uf/3.0;
+            t = 1.0;
+            while( (double)(t)>(double)(AP.Math.MachineEpsilon) )
+            {
+                uf = uf*z;
+                ug = ug/k;
+                k = k+1.0;
+                ug = ug*z;
+                uf = uf/k;
+                f = f+uf;
+                k = k+1.0;
+                ug = ug/k;
+                uf = uf/k;
+                g = g+ug;
+                k = k+1.0;
+                t = Math.Abs(ug/g);
+            }
+            uf = c1*f;
+            ug = c2*g;
+            if( domflg/4%2==0 )
+            {
+                aip = uf-ug;
+            }
+            if( domflg/8%2==0 )
+            {
+                bip = sqrt3*(uf+ug);
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ap.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ap.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ap.cs	(revision 2645)
@@ -0,0 +1,195 @@
+/*************************************************************************
+AP library
+Copyright (c) 2003-2009 Sergey Bochkanov (ALGLIB project).
+
+>>> LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+namespace AP
+{
+    /********************************************************************
+    Class defining a complex number with double precision.
+    ********************************************************************/
+    public struct Complex
+    {
+        public double x;
+        public double y;
+
+        public Complex(double _x)
+        {
+            x = _x;
+            y = 0;
+        }
+        public Complex(double _x, double _y)
+        {
+            x = _x;
+            y = _y;
+        }
+        public static implicit operator Complex(double _x)
+        {
+            return new Complex(_x);
+        }
+        public static bool operator==(Complex lhs, Complex rhs)
+        {
+            return ((double)lhs.x==(double)rhs.x) & ((double)lhs.y==(double)rhs.y);
+        }
+        public static bool operator!=(Complex lhs, Complex rhs)
+        {
+            return ((double)lhs.x!=(double)rhs.x) | ((double)lhs.y!=(double)rhs.y);
+        }
+        public static Complex operator+(Complex lhs)
+        {
+            return lhs;
+        }
+        public static Complex operator-(Complex lhs)
+        {
+            return new Complex(-lhs.x,-lhs.y);
+        }
+        public static Complex operator+(Complex lhs, Complex rhs)
+        {
+            return new Complex(lhs.x+rhs.x,lhs.y+rhs.y);
+        }
+        public static Complex operator-(Complex lhs, Complex rhs)
+        {
+            return new Complex(lhs.x-rhs.x,lhs.y-rhs.y);
+        }
+        public static Complex operator*(Complex lhs, Complex rhs)
+        { 
+            return new Complex(lhs.x*rhs.x-lhs.y*rhs.y, lhs.x*rhs.y+lhs.y*rhs.x);
+        }
+        public static Complex operator/(Complex lhs, Complex rhs)
+        {
+            Complex result;
+            double e;
+            double f;
+            if( System.Math.Abs(rhs.y)<System.Math.Abs(rhs.x) )
+            {
+                e = rhs.y/rhs.x;
+                f = rhs.x+rhs.y*e;
+                result.x = (lhs.x+lhs.y*e)/f;
+                result.y = (lhs.y-lhs.x*e)/f;
+            }
+            else
+            {
+                e = rhs.x/rhs.y;
+                f = rhs.y+rhs.x*e;
+                result.x = (lhs.y+lhs.x*e)/f;
+                result.y = (-lhs.x+lhs.y*e)/f;
+            }
+            return result;
+        }
+		public override int GetHashCode() 
+		{ 
+			return x.GetHashCode() ^ y.GetHashCode(); 
+		}
+		public override bool Equals(object obj) 
+		{ 
+			if( obj is byte)
+				return Equals(new Complex((byte)obj));
+			if( obj is sbyte)
+				return Equals(new Complex((sbyte)obj));
+			if( obj is short)
+				return Equals(new Complex((short)obj));
+			if( obj is ushort)
+				return Equals(new Complex((ushort)obj));
+			if( obj is int)
+				return Equals(new Complex((int)obj));
+			if( obj is uint)
+				return Equals(new Complex((uint)obj));
+			if( obj is long)
+				return Equals(new Complex((long)obj));
+			if( obj is ulong)
+				return Equals(new Complex((ulong)obj));
+			if( obj is float)
+				return Equals(new Complex((float)obj));
+			if( obj is double)
+				return Equals(new Complex((double)obj));
+			if( obj is decimal)
+				return Equals(new Complex((double)(decimal)obj));
+			return base.Equals(obj); 
+		}	
+	}    
+    
+	/********************************************************************
+	AP math namespace
+	********************************************************************/
+	public struct rcommstate
+	{
+		public int stage;
+		public int[] ia;
+		public bool[] ba;
+		public double[] ra;
+		public AP.Complex[] ca;
+	};
+
+	/********************************************************************
+    AP math namespace
+    ********************************************************************/
+    public class Math
+    {
+        //public static System.Random RndObject = new System.Random(System.DateTime.Now.Millisecond);
+        public static System.Random RndObject = new System.Random(System.DateTime.Now.Millisecond + 1000*System.DateTime.Now.Second + 60*1000*System.DateTime.Now.Minute);
+
+        public const double MachineEpsilon = 5E-16;
+        public const double MaxRealNumber = 1E300;
+        public const double MinRealNumber = 1E-300;
+        
+        public static double RandomReal()
+        {
+            double r = 0;
+            lock(RndObject){ r = RndObject.NextDouble(); }
+            return r;
+        }
+        public static int RandomInteger(int N)
+        {
+            int r = 0;
+            lock(RndObject){ r = RndObject.Next(N); }
+            return r;
+        }
+        public static double Sqr(double X)
+        {
+            return X*X;
+        }        
+        public static double AbsComplex(Complex z)
+        {
+            double w;
+            double xabs;
+            double yabs;
+            double v;
+    
+            xabs = System.Math.Abs(z.x);
+            yabs = System.Math.Abs(z.y);
+            w = xabs>yabs ? xabs : yabs;
+            v = xabs<yabs ? xabs : yabs; 
+            if( v==0 )
+                return w;
+            else
+            {
+                double t = v/w;
+                return w*System.Math.Sqrt(1+t*t);
+            }
+        }
+        public static Complex Conj(Complex z)
+        {
+            return new Complex(z.x, -z.y); 
+        }    
+        public static Complex CSqr(Complex z)
+        {
+            return new Complex(z.x*z.x-z.y*z.y, 2*z.x*z.y); 
+        }
+
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ap.english.html
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ap.english.html	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ap.english.html	(revision 2645)
@@ -0,0 +1,100 @@
+<html>
+<head>
+
+<title>AP Library adapted for C#</title>
+<style type="text/css">
+<!--
+h1 { font-family: Tahoma,sans-serif; font-size : larger; }
+h2 { font-family: Arial,sans-serif; font-size : 11pt; }
+h3 { font-family: Arial,sans-serif; font-size : 9pt; }
+.cond  { color:blue; }
+.const { color:#222222; }
+.func  { color:#111111; }
+-->
+</style>
+</head>
+<body>
+
+<h1>AP Library adapted for C#</h1>
+
+<p align=justify>
+The document describes an AP library adapted for C#. The AP library for C# contains a basic set of mathematical functions and collection classes needed to run the programs from the <a href="http://www.alglib.net/">ALGLIB</a> website.
+</p>
+
+<h1>Compatibility</h1>
+
+<p align=justify>
+This library must be compatible with any C# compiler.
+</p>
+
+<h1>Structure and Use</h1>
+
+<p align=justify>
+The library includes the only file <code>ap.cs</code>
+</p>
+
+<h1>AP Library Description</h1>
+
+<font size=-1>
+<a href="#constants">Constants</a><br>
+<a href="#functions">Functions</a><br>
+<a href="#complex">Complex numbers</a><br>
+</font>
+
+<a name="constants"><h1>Constants</h1></a>
+
+<p align=justify>
+<span class=const>AP.Math.MachineEpsilon</span><br>
+The constant represents the accuracy of machine operations, that is the minimum number for <code>1+machineepsilon&ne;1</code> in the given bit grid. The constant may be taken &quot;oversized&quot;, that is real accuracy can be even higher.
+</p>
+
+<p align=justify>
+<span class=const>AP.Math.MaxRealNumber</span><br>
+The constant represents the highest value of the positive real number, which could be represented on this machine. The constant may be taken &quot;oversized&quot;, that is real boundary can be even higher.
+</p>
+
+<p align=justify>
+<span class=const>AP.Math.MinRealNumber</span><br>
+The constant represents the lowest value of positive real number, which could be represented on this machine. The constant may be taken &quot;oversized&quot;, that is real boundary can be even lower.
+</p>
+
+<a name="functions"><h1>Functions</h1></a>
+
+<p align=justify>
+<span class=func><b>public static double</b> AP.Math.RandomReal()</span><br>
+Returns a random real number from half-interval [0,1).
+</p>
+
+<p align=justify>
+<span class=func><b>public static int</b> AP.Math.RandomInteger(<b>int</b> N)</span><br>
+Returns a random integer between 0 and maxv-1.
+</p>
+
+<p align=justify>
+<span class=func><b>public static double</b> AP.Math.Sqr(<b>double</b> x)</span><br>
+Returns x<sup>2</sup>.
+</p>
+
+<a name="complex"><h1>Class of complex numbers</h1></a>
+
+<p align=justify>
+AP library includes the <code>AP.Complex</code> structure that supports operations with compex numbers. Access to real and imaginary parts of complex number is implemented through the public fields <code>x</code> and <code>y</code>. Arithmetical operations are supported, the same as with embedded data types, by overloading of operations: addition, subtraction, multiplication and division. Addition, subtraction and multiplication are performed by a usual way (i.e., according to their definition which can be found in any textdook in algebra), division is performed using so called &quot;safe&quot; algorithm that could never cause overflow when calculating intermediate results. The library also includes several functions performing elementary operations with complex numbers.
+</p>
+
+<p align=justify>
+<span class=func><b>double</b> AP.Math.AbsComplex(AP.Complex z)</span><br>
+Returns the modulus of complex number z. It should be noted that the modulus calculation is performed using so called &quot;safe&quot; algorithm, that could never cause overflow when calculating intermediate results.
+</p>
+
+<p align=justify>
+<span class=func>AP.Complex AP.Math.Conj(AP.Complex z)</span><br>
+Returns complex conjugate to z.
+</p>
+
+<p align=justify>
+<span class=func>AP.Complex AP.Math.CSqr(AP.Complex z)</span><br>
+Returns the square of z.
+</p>
+
+</body>
+</html>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/autogk.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/autogk.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/autogk.cs	(revision 2645)
@@ -0,0 +1,1145 @@
+/*************************************************************************
+Copyright (c) 2005-2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class autogk
+    {
+        /*************************************************************************
+        Integration report:
+        * TerminationType = completetion code:
+            * -5    non-convergence of Gauss-Kronrod nodes
+                    calculation subroutine.
+            * -1    incorrect parameters were specified
+            *  1    OK
+        * Rep.NFEV countains number of function calculations
+        * Rep.NIntervals contains number of intervals [a,b]
+          was partitioned into.
+        *************************************************************************/
+        public struct autogkreport
+        {
+            public int terminationtype;
+            public int nfev;
+            public int nintervals;
+        };
+
+
+        public struct autogkinternalstate
+        {
+            public double a;
+            public double b;
+            public double eps;
+            public double xwidth;
+            public double x;
+            public double f;
+            public int info;
+            public double r;
+            public double[,] heap;
+            public int heapsize;
+            public int heapwidth;
+            public int heapused;
+            public double sumerr;
+            public double sumabs;
+            public double[] qn;
+            public double[] wg;
+            public double[] wk;
+            public double[] wr;
+            public int n;
+            public AP.rcommstate rstate;
+        };
+
+
+        /*************************************************************************
+        This structure stores internal state of the integration algorithm  between
+        subsequent calls of the AutoGKIteration() subroutine.
+        *************************************************************************/
+        public struct autogkstate
+        {
+            public double a;
+            public double b;
+            public double alpha;
+            public double beta;
+            public double xwidth;
+            public double x;
+            public double xminusa;
+            public double bminusx;
+            public double f;
+            public int wrappermode;
+            public autogkinternalstate internalstate;
+            public AP.rcommstate rstate;
+            public double v;
+            public int terminationtype;
+            public int nfev;
+            public int nintervals;
+        };
+
+
+
+
+        /*************************************************************************
+        Integration of a smooth function F(x) on a finite interval [a,b].
+
+        Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result
+        is calculated with accuracy close to the machine precision.
+
+        Algorithm works well only with smooth integrands.  It  may  be  used  with
+        continuous non-smooth integrands, but with  less  performance.
+
+        It should never be used with integrands which have integrable singularities
+        at lower or upper limits - algorithm may crash. Use AutoGKSingular in such
+        cases.
+
+        INPUT PARAMETERS:
+            A, B    -   interval boundaries (A<B, A=B or A>B)
+            
+        OUTPUT PARAMETERS
+            State   -   structure which stores algorithm state between  subsequent
+                        calls of AutoGKIteration.  Used for reverse communication.
+                        This structure should be  passed  to  the  AutoGKIteration
+                        subroutine.
+
+        SEE ALSO
+            AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults.
+            
+
+          -- ALGLIB --
+             Copyright 06.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void autogksmooth(double a,
+            double b,
+            ref autogkstate state)
+        {
+            autogksmoothw(a, b, 0.0, ref state);
+        }
+
+
+        /*************************************************************************
+        Integration of a smooth function F(x) on a finite interval [a,b].
+
+        This subroutine is same as AutoGKSmooth(), but it guarantees that interval
+        [a,b] is partitioned into subintervals which have width at most XWidth.
+
+        Subroutine  can  be  used  when  integrating nearly-constant function with
+        narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth
+        subroutine can overlook them.
+
+        INPUT PARAMETERS:
+            A, B    -   interval boundaries (A<B, A=B or A>B)
+
+        OUTPUT PARAMETERS
+            State   -   structure which stores algorithm state between  subsequent
+                        calls of AutoGKIteration.  Used for reverse communication.
+                        This structure should be  passed  to  the  AutoGKIteration
+                        subroutine.
+
+        SEE ALSO
+            AutoGKSmooth, AutoGKSingular, AutoGKIteration, AutoGKResults.
+
+
+          -- ALGLIB --
+             Copyright 06.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void autogksmoothw(double a,
+            double b,
+            double xwidth,
+            ref autogkstate state)
+        {
+            state.wrappermode = 0;
+            state.a = a;
+            state.b = b;
+            state.xwidth = xwidth;
+            state.rstate.ra = new double[10+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        Integration on a finite interval [A,B].
+        Integrand have integrable singularities at A/B.
+
+        F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B,  with known
+        alpha/beta (alpha>-1, beta>-1).  If alpha/beta  are  not known,  estimates
+        from below can be used (but these estimates should be greater than -1 too).
+
+        One  of  alpha/beta variables (or even both alpha/beta) may be equal to 0,
+        which means than function F(x) is non-singular at A/B. Anyway (singular at
+        bounds or not), function F(x) is supposed to be continuous on (A,B).
+
+        Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result
+        is calculated with accuracy close to the machine precision.
+
+        INPUT PARAMETERS:
+            A, B    -   interval boundaries (A<B, A=B or A>B)
+            Alpha   -   power-law coefficient of the F(x) at A,
+                        Alpha>-1
+            Beta    -   power-law coefficient of the F(x) at B,
+                        Beta>-1
+
+        OUTPUT PARAMETERS
+            State   -   structure which stores algorithm state between  subsequent
+                        calls of AutoGKIteration.  Used for reverse communication.
+                        This structure should be  passed  to  the  AutoGKIteration
+                        subroutine.
+
+        SEE ALSO
+            AutoGKSmooth, AutoGKSmoothW, AutoGKIteration, AutoGKResults.
+
+
+          -- ALGLIB --
+             Copyright 06.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void autogksingular(double a,
+            double b,
+            double alpha,
+            double beta,
+            ref autogkstate state)
+        {
+            state.wrappermode = 1;
+            state.a = a;
+            state.b = b;
+            state.alpha = alpha;
+            state.beta = beta;
+            state.xwidth = 0.0;
+            state.rstate.ra = new double[10+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        One step of adaptive integration process.
+
+        Called after initialization with one of AutoGKXXX subroutines.
+        See HTML documentation for examples.
+
+        Input parameters:
+            State   -   structure which stores algorithm state between  calls  and
+                        which  is  used  for   reverse   communication.   Must  be
+                        initialized with one of AutoGKXXX subroutines.
+
+        If suborutine returned False, iterative proces has converged. If subroutine
+        returned True, caller should calculate function value State.F  at  State.X
+        and call AutoGKIteration again.
+
+        NOTE:
+
+        When integrating "difficult" functions with integrable singularities like
+
+            F(x) = (x-A)^alpha * (B-x)^beta
+
+        subroutine may require the value of F at points which are too close to A/B.
+        Sometimes to calculate integral with high enough precision we  may need to
+        calculate F(A+delta) when delta is less than machine  epsilon.  In  finite
+        precision arithmetics A+delta will be effectively equal to A,  so  we  may
+        find us in situation when  we  are  trying  to  calculate  something  like
+        1/sqrt(1-1).
+
+        To avoid  such  situations,  AutoGKIteration  subroutine  fills  not  only
+        State.X  field,  but  also   State.XMinusA   (which  equals  to  X-A)  and
+        State.BMinusX  (which  equals to B-X) fields.  If X is too close to A or B
+        (X-A<0.001*A, or B-X<0.001*B, for example) use  these  fields  instead  of
+        State.X
+
+
+          -- ALGLIB --
+             Copyright 07.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool autogkiteration(ref autogkstate state)
+        {
+            bool result = new bool();
+            double s = 0;
+            double tmp = 0;
+            double eps = 0;
+            double a = 0;
+            double b = 0;
+            double x = 0;
+            double t = 0;
+            double alpha = 0;
+            double beta = 0;
+            double v1 = 0;
+            double v2 = 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.rstate.stage>=0 )
+            {
+                s = state.rstate.ra[0];
+                tmp = state.rstate.ra[1];
+                eps = state.rstate.ra[2];
+                a = state.rstate.ra[3];
+                b = state.rstate.ra[4];
+                x = state.rstate.ra[5];
+                t = state.rstate.ra[6];
+                alpha = state.rstate.ra[7];
+                beta = state.rstate.ra[8];
+                v1 = state.rstate.ra[9];
+                v2 = state.rstate.ra[10];
+            }
+            else
+            {
+                s = -983;
+                tmp = -989;
+                eps = -834;
+                a = 900;
+                b = -287;
+                x = 364;
+                t = 214;
+                alpha = -338;
+                beta = -686;
+                v1 = 912;
+                v2 = 585;
+            }
+            if( state.rstate.stage==0 )
+            {
+                goto lbl_0;
+            }
+            if( state.rstate.stage==1 )
+            {
+                goto lbl_1;
+            }
+            if( state.rstate.stage==2 )
+            {
+                goto lbl_2;
+            }
+            
+            //
+            // Routine body
+            //
+            eps = 0;
+            a = state.a;
+            b = state.b;
+            alpha = state.alpha;
+            beta = state.beta;
+            state.terminationtype = -1;
+            state.nfev = 0;
+            state.nintervals = 0;
+            
+            //
+            // smooth function  at a finite interval
+            //
+            if( state.wrappermode!=0 )
+            {
+                goto lbl_3;
+            }
+            
+            //
+            // special case
+            //
+            if( (double)(a)==(double)(b) )
+            {
+                state.terminationtype = 1;
+                state.v = 0;
+                result = false;
+                return result;
+            }
+            
+            //
+            // general case
+            //
+            autogkinternalprepare(a, b, eps, state.xwidth, ref state.internalstate);
+        lbl_5:
+            if( ! autogkinternaliteration(ref state.internalstate) )
+            {
+                goto lbl_6;
+            }
+            x = state.internalstate.x;
+            state.x = x;
+            state.xminusa = x-a;
+            state.bminusx = b-x;
+            state.rstate.stage = 0;
+            goto lbl_rcomm;
+        lbl_0:
+            state.nfev = state.nfev+1;
+            state.internalstate.f = state.f;
+            goto lbl_5;
+        lbl_6:
+            state.v = state.internalstate.r;
+            state.terminationtype = state.internalstate.info;
+            state.nintervals = state.internalstate.heapused;
+            result = false;
+            return result;
+        lbl_3:
+            
+            //
+            // function with power-law singularities at the ends of a finite interval
+            //
+            if( state.wrappermode!=1 )
+            {
+                goto lbl_7;
+            }
+            
+            //
+            // test coefficients
+            //
+            if( (double)(alpha)<=(double)(-1) | (double)(beta)<=(double)(-1) )
+            {
+                state.terminationtype = -1;
+                state.v = 0;
+                result = false;
+                return result;
+            }
+            
+            //
+            // special cases
+            //
+            if( (double)(a)==(double)(b) )
+            {
+                state.terminationtype = 1;
+                state.v = 0;
+                result = false;
+                return result;
+            }
+            
+            //
+            // reduction to general form
+            //
+            if( (double)(a)<(double)(b) )
+            {
+                s = +1;
+            }
+            else
+            {
+                s = -1;
+                tmp = a;
+                a = b;
+                b = tmp;
+                tmp = alpha;
+                alpha = beta;
+                beta = tmp;
+            }
+            alpha = Math.Min(alpha, 0);
+            beta = Math.Min(beta, 0);
+            
+            //
+            // first, integrate left half of [a,b]:
+            //     integral(f(x)dx, a, (b+a)/2) =
+            //     = 1/(1+alpha) * integral(t^(-alpha/(1+alpha))*f(a+t^(1/(1+alpha)))dt, 0, (0.5*(b-a))^(1+alpha))
+            //
+            autogkinternalprepare(0, Math.Pow(0.5*(b-a), 1+alpha), eps, state.xwidth, ref state.internalstate);
+        lbl_9:
+            if( ! autogkinternaliteration(ref state.internalstate) )
+            {
+                goto lbl_10;
+            }
+            
+            //
+            // Fill State.X, State.XMinusA, State.BMinusX.
+            // Latter two are filled correctly even if B<A.
+            //
+            x = state.internalstate.x;
+            t = Math.Pow(x, 1/(1+alpha));
+            state.x = a+t;
+            if( (double)(s)>(double)(0) )
+            {
+                state.xminusa = t;
+                state.bminusx = b-(a+t);
+            }
+            else
+            {
+                state.xminusa = a+t-b;
+                state.bminusx = -t;
+            }
+            state.rstate.stage = 1;
+            goto lbl_rcomm;
+        lbl_1:
+            if( (double)(alpha)!=(double)(0) )
+            {
+                state.internalstate.f = state.f*Math.Pow(x, -(alpha/(1+alpha)))/(1+alpha);
+            }
+            else
+            {
+                state.internalstate.f = state.f;
+            }
+            state.nfev = state.nfev+1;
+            goto lbl_9;
+        lbl_10:
+            v1 = state.internalstate.r;
+            state.nintervals = state.nintervals+state.internalstate.heapused;
+            
+            //
+            // then, integrate right half of [a,b]:
+            //     integral(f(x)dx, (b+a)/2, b) =
+            //     = 1/(1+beta) * integral(t^(-beta/(1+beta))*f(b-t^(1/(1+beta)))dt, 0, (0.5*(b-a))^(1+beta))
+            //
+            autogkinternalprepare(0, Math.Pow(0.5*(b-a), 1+beta), eps, state.xwidth, ref state.internalstate);
+        lbl_11:
+            if( ! autogkinternaliteration(ref state.internalstate) )
+            {
+                goto lbl_12;
+            }
+            
+            //
+            // Fill State.X, State.XMinusA, State.BMinusX.
+            // Latter two are filled correctly (X-A, B-X) even if B<A.
+            //
+            x = state.internalstate.x;
+            t = Math.Pow(x, 1/(1+beta));
+            state.x = b-t;
+            if( (double)(s)>(double)(0) )
+            {
+                state.xminusa = b-t-a;
+                state.bminusx = t;
+            }
+            else
+            {
+                state.xminusa = -t;
+                state.bminusx = a-(b-t);
+            }
+            state.rstate.stage = 2;
+            goto lbl_rcomm;
+        lbl_2:
+            if( (double)(beta)!=(double)(0) )
+            {
+                state.internalstate.f = state.f*Math.Pow(x, -(beta/(1+beta)))/(1+beta);
+            }
+            else
+            {
+                state.internalstate.f = state.f;
+            }
+            state.nfev = state.nfev+1;
+            goto lbl_11;
+        lbl_12:
+            v2 = state.internalstate.r;
+            state.nintervals = state.nintervals+state.internalstate.heapused;
+            
+            //
+            // final result
+            //
+            state.v = s*(v1+v2);
+            state.terminationtype = 1;
+            result = false;
+            return result;
+        lbl_7:
+            result = false;
+            return result;
+            
+            //
+            // Saving state
+            //
+        lbl_rcomm:
+            result = true;
+            state.rstate.ra[0] = s;
+            state.rstate.ra[1] = tmp;
+            state.rstate.ra[2] = eps;
+            state.rstate.ra[3] = a;
+            state.rstate.ra[4] = b;
+            state.rstate.ra[5] = x;
+            state.rstate.ra[6] = t;
+            state.rstate.ra[7] = alpha;
+            state.rstate.ra[8] = beta;
+            state.rstate.ra[9] = v1;
+            state.rstate.ra[10] = v2;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Adaptive integration results
+
+        Called after AutoGKIteration returned False.
+
+        Input parameters:
+            State   -   algorithm state (used by AutoGKIteration).
+
+        Output parameters:
+            V       -   integral(f(x)dx,a,b)
+            Rep     -   optimization report (see AutoGKReport description)
+
+          -- ALGLIB --
+             Copyright 14.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void autogkresults(ref autogkstate state,
+            ref double v,
+            ref autogkreport rep)
+        {
+            v = state.v;
+            rep.terminationtype = state.terminationtype;
+            rep.nfev = state.nfev;
+            rep.nintervals = state.nintervals;
+        }
+
+
+        /*************************************************************************
+        Internal AutoGK subroutine
+        eps<0   - error
+        eps=0   - automatic eps selection
+
+        width<0 -   error
+        width=0 -   no width requirements
+        *************************************************************************/
+        private static void autogkinternalprepare(double a,
+            double b,
+            double eps,
+            double xwidth,
+            ref autogkinternalstate state)
+        {
+            
+            //
+            // Save settings
+            //
+            state.a = a;
+            state.b = b;
+            state.eps = eps;
+            state.xwidth = xwidth;
+            
+            //
+            // Prepare RComm structure
+            //
+            state.rstate.ia = new int[3+1];
+            state.rstate.ra = new double[8+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        Internal AutoGK subroutine
+        *************************************************************************/
+        private static bool autogkinternaliteration(ref autogkinternalstate state)
+        {
+            bool result = new bool();
+            double c1 = 0;
+            double c2 = 0;
+            int i = 0;
+            int j = 0;
+            double intg = 0;
+            double intk = 0;
+            double inta = 0;
+            double v = 0;
+            double ta = 0;
+            double tb = 0;
+            int ns = 0;
+            double qeps = 0;
+            int info = 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.rstate.stage>=0 )
+            {
+                i = state.rstate.ia[0];
+                j = state.rstate.ia[1];
+                ns = state.rstate.ia[2];
+                info = state.rstate.ia[3];
+                c1 = state.rstate.ra[0];
+                c2 = state.rstate.ra[1];
+                intg = state.rstate.ra[2];
+                intk = state.rstate.ra[3];
+                inta = state.rstate.ra[4];
+                v = state.rstate.ra[5];
+                ta = state.rstate.ra[6];
+                tb = state.rstate.ra[7];
+                qeps = state.rstate.ra[8];
+            }
+            else
+            {
+                i = 497;
+                j = -271;
+                ns = -581;
+                info = 745;
+                c1 = -533;
+                c2 = -77;
+                intg = 678;
+                intk = -293;
+                inta = 316;
+                v = 647;
+                ta = -756;
+                tb = 830;
+                qeps = -871;
+            }
+            if( state.rstate.stage==0 )
+            {
+                goto lbl_0;
+            }
+            if( state.rstate.stage==1 )
+            {
+                goto lbl_1;
+            }
+            if( state.rstate.stage==2 )
+            {
+                goto lbl_2;
+            }
+            
+            //
+            // Routine body
+            //
+            
+            //
+            // initialize quadratures.
+            // use 15-point Gauss-Kronrod formula.
+            //
+            state.n = 15;
+            gkq.gkqgenerategausslegendre(state.n, ref info, ref state.qn, ref state.wk, ref state.wg);
+            if( info<0 )
+            {
+                state.info = -5;
+                state.r = 0;
+                result = false;
+                return result;
+            }
+            state.wr = new double[state.n];
+            for(i=0; i<=state.n-1; i++)
+            {
+                if( i==0 )
+                {
+                    state.wr[i] = 0.5*Math.Abs(state.qn[1]-state.qn[0]);
+                    continue;
+                }
+                if( i==state.n-1 )
+                {
+                    state.wr[state.n-1] = 0.5*Math.Abs(state.qn[state.n-1]-state.qn[state.n-2]);
+                    continue;
+                }
+                state.wr[i] = 0.5*Math.Abs(state.qn[i-1]-state.qn[i+1]);
+            }
+            
+            //
+            // special case
+            //
+            if( (double)(state.a)==(double)(state.b) )
+            {
+                state.info = 1;
+                state.r = 0;
+                result = false;
+                return result;
+            }
+            
+            //
+            // test parameters
+            //
+            if( (double)(state.eps)<(double)(0) | (double)(state.xwidth)<(double)(0) )
+            {
+                state.info = -1;
+                state.r = 0;
+                result = false;
+                return result;
+            }
+            state.info = 1;
+            if( (double)(state.eps)==(double)(0) )
+            {
+                state.eps = 1000*AP.Math.MachineEpsilon;
+            }
+            
+            //
+            // First, prepare heap
+            // * column 0   -   absolute error
+            // * column 1   -   integral of a F(x) (calculated using Kronrod extension nodes)
+            // * column 2   -   integral of a |F(x)| (calculated using modified rect. method)
+            // * column 3   -   left boundary of a subinterval
+            // * column 4   -   right boundary of a subinterval
+            //
+            if( (double)(state.xwidth)!=(double)(0) )
+            {
+                goto lbl_3;
+            }
+            
+            //
+            // no maximum width requirements
+            // start from one big subinterval
+            //
+            state.heapwidth = 5;
+            state.heapsize = 1;
+            state.heapused = 1;
+            state.heap = new double[state.heapsize, state.heapwidth];
+            c1 = 0.5*(state.b-state.a);
+            c2 = 0.5*(state.b+state.a);
+            intg = 0;
+            intk = 0;
+            inta = 0;
+            i = 0;
+        lbl_5:
+            if( i>state.n-1 )
+            {
+                goto lbl_7;
+            }
+            
+            //
+            // obtain F
+            //
+            state.x = c1*state.qn[i]+c2;
+            state.rstate.stage = 0;
+            goto lbl_rcomm;
+        lbl_0:
+            v = state.f;
+            
+            //
+            // Gauss-Kronrod formula
+            //
+            intk = intk+v*state.wk[i];
+            if( i%2==1 )
+            {
+                intg = intg+v*state.wg[i];
+            }
+            
+            //
+            // Integral |F(x)|
+            // Use rectangles method
+            //
+            inta = inta+Math.Abs(v)*state.wr[i];
+            i = i+1;
+            goto lbl_5;
+        lbl_7:
+            intk = intk*(state.b-state.a)*0.5;
+            intg = intg*(state.b-state.a)*0.5;
+            inta = inta*(state.b-state.a)*0.5;
+            state.heap[0,0] = Math.Abs(intg-intk);
+            state.heap[0,1] = intk;
+            state.heap[0,2] = inta;
+            state.heap[0,3] = state.a;
+            state.heap[0,4] = state.b;
+            state.sumerr = state.heap[0,0];
+            state.sumabs = Math.Abs(inta);
+            goto lbl_4;
+        lbl_3:
+            
+            //
+            // maximum subinterval should be no more than XWidth.
+            // so we create Ceil((B-A)/XWidth)+1 small subintervals
+            //
+            ns = (int)Math.Ceiling(Math.Abs(state.b-state.a)/state.xwidth)+1;
+            state.heapsize = ns;
+            state.heapused = ns;
+            state.heapwidth = 5;
+            state.heap = new double[state.heapsize, state.heapwidth];
+            state.sumerr = 0;
+            state.sumabs = 0;
+            j = 0;
+        lbl_8:
+            if( j>ns-1 )
+            {
+                goto lbl_10;
+            }
+            ta = state.a+j*(state.b-state.a)/ns;
+            tb = state.a+(j+1)*(state.b-state.a)/ns;
+            c1 = 0.5*(tb-ta);
+            c2 = 0.5*(tb+ta);
+            intg = 0;
+            intk = 0;
+            inta = 0;
+            i = 0;
+        lbl_11:
+            if( i>state.n-1 )
+            {
+                goto lbl_13;
+            }
+            
+            //
+            // obtain F
+            //
+            state.x = c1*state.qn[i]+c2;
+            state.rstate.stage = 1;
+            goto lbl_rcomm;
+        lbl_1:
+            v = state.f;
+            
+            //
+            // Gauss-Kronrod formula
+            //
+            intk = intk+v*state.wk[i];
+            if( i%2==1 )
+            {
+                intg = intg+v*state.wg[i];
+            }
+            
+            //
+            // Integral |F(x)|
+            // Use rectangles method
+            //
+            inta = inta+Math.Abs(v)*state.wr[i];
+            i = i+1;
+            goto lbl_11;
+        lbl_13:
+            intk = intk*(tb-ta)*0.5;
+            intg = intg*(tb-ta)*0.5;
+            inta = inta*(tb-ta)*0.5;
+            state.heap[j,0] = Math.Abs(intg-intk);
+            state.heap[j,1] = intk;
+            state.heap[j,2] = inta;
+            state.heap[j,3] = ta;
+            state.heap[j,4] = tb;
+            state.sumerr = state.sumerr+state.heap[j,0];
+            state.sumabs = state.sumabs+Math.Abs(inta);
+            j = j+1;
+            goto lbl_8;
+        lbl_10:
+        lbl_4:
+            
+            //
+            // method iterations
+            //
+        lbl_14:
+            if( false )
+            {
+                goto lbl_15;
+            }
+            
+            //
+            // additional memory if needed
+            //
+            if( state.heapused==state.heapsize )
+            {
+                mheapresize(ref state.heap, ref state.heapsize, 4*state.heapsize, state.heapwidth);
+            }
+            
+            //
+            // TODO: every 20 iterations recalculate errors/sums
+            // TODO: one more criterion to prevent infinite loops with too strict Eps
+            //
+            if( (double)(state.sumerr)<=(double)(state.eps*state.sumabs) )
+            {
+                state.r = 0;
+                for(j=0; j<=state.heapused-1; j++)
+                {
+                    state.r = state.r+state.heap[j,1];
+                }
+                result = false;
+                return result;
+            }
+            
+            //
+            // Exclude interval with maximum absolute error
+            //
+            mheappop(ref state.heap, state.heapused, state.heapwidth);
+            state.sumerr = state.sumerr-state.heap[state.heapused-1,0];
+            state.sumabs = state.sumabs-state.heap[state.heapused-1,2];
+            
+            //
+            // Divide interval, create subintervals
+            //
+            ta = state.heap[state.heapused-1,3];
+            tb = state.heap[state.heapused-1,4];
+            state.heap[state.heapused-1,3] = ta;
+            state.heap[state.heapused-1,4] = 0.5*(ta+tb);
+            state.heap[state.heapused,3] = 0.5*(ta+tb);
+            state.heap[state.heapused,4] = tb;
+            j = state.heapused-1;
+        lbl_16:
+            if( j>state.heapused )
+            {
+                goto lbl_18;
+            }
+            c1 = 0.5*(state.heap[j,4]-state.heap[j,3]);
+            c2 = 0.5*(state.heap[j,4]+state.heap[j,3]);
+            intg = 0;
+            intk = 0;
+            inta = 0;
+            i = 0;
+        lbl_19:
+            if( i>state.n-1 )
+            {
+                goto lbl_21;
+            }
+            
+            //
+            // F(x)
+            //
+            state.x = c1*state.qn[i]+c2;
+            state.rstate.stage = 2;
+            goto lbl_rcomm;
+        lbl_2:
+            v = state.f;
+            
+            //
+            // Gauss-Kronrod formula
+            //
+            intk = intk+v*state.wk[i];
+            if( i%2==1 )
+            {
+                intg = intg+v*state.wg[i];
+            }
+            
+            //
+            // Integral |F(x)|
+            // Use rectangles method
+            //
+            inta = inta+Math.Abs(v)*state.wr[i];
+            i = i+1;
+            goto lbl_19;
+        lbl_21:
+            intk = intk*(state.heap[j,4]-state.heap[j,3])*0.5;
+            intg = intg*(state.heap[j,4]-state.heap[j,3])*0.5;
+            inta = inta*(state.heap[j,4]-state.heap[j,3])*0.5;
+            state.heap[j,0] = Math.Abs(intg-intk);
+            state.heap[j,1] = intk;
+            state.heap[j,2] = inta;
+            state.sumerr = state.sumerr+state.heap[j,0];
+            state.sumabs = state.sumabs+state.heap[j,2];
+            j = j+1;
+            goto lbl_16;
+        lbl_18:
+            mheappush(ref state.heap, state.heapused-1, state.heapwidth);
+            mheappush(ref state.heap, state.heapused, state.heapwidth);
+            state.heapused = state.heapused+1;
+            goto lbl_14;
+        lbl_15:
+            result = false;
+            return result;
+            
+            //
+            // Saving state
+            //
+        lbl_rcomm:
+            result = true;
+            state.rstate.ia[0] = i;
+            state.rstate.ia[1] = j;
+            state.rstate.ia[2] = ns;
+            state.rstate.ia[3] = info;
+            state.rstate.ra[0] = c1;
+            state.rstate.ra[1] = c2;
+            state.rstate.ra[2] = intg;
+            state.rstate.ra[3] = intk;
+            state.rstate.ra[4] = inta;
+            state.rstate.ra[5] = v;
+            state.rstate.ra[6] = ta;
+            state.rstate.ra[7] = tb;
+            state.rstate.ra[8] = qeps;
+            return result;
+        }
+
+
+        private static void mheappop(ref double[,] heap,
+            int heapsize,
+            int heapwidth)
+        {
+            int i = 0;
+            int p = 0;
+            double t = 0;
+            int maxcp = 0;
+
+            if( heapsize==1 )
+            {
+                return;
+            }
+            for(i=0; i<=heapwidth-1; i++)
+            {
+                t = heap[heapsize-1,i];
+                heap[heapsize-1,i] = heap[0,i];
+                heap[0,i] = t;
+            }
+            p = 0;
+            while( 2*p+1<heapsize-1 )
+            {
+                maxcp = 2*p+1;
+                if( 2*p+2<heapsize-1 )
+                {
+                    if( (double)(heap[2*p+2,0])>(double)(heap[2*p+1,0]) )
+                    {
+                        maxcp = 2*p+2;
+                    }
+                }
+                if( (double)(heap[p,0])<(double)(heap[maxcp,0]) )
+                {
+                    for(i=0; i<=heapwidth-1; i++)
+                    {
+                        t = heap[p,i];
+                        heap[p,i] = heap[maxcp,i];
+                        heap[maxcp,i] = t;
+                    }
+                    p = maxcp;
+                }
+                else
+                {
+                    break;
+                }
+            }
+        }
+
+
+        private static void mheappush(ref double[,] heap,
+            int heapsize,
+            int heapwidth)
+        {
+            int i = 0;
+            int p = 0;
+            double t = 0;
+            int parent = 0;
+
+            if( heapsize==0 )
+            {
+                return;
+            }
+            p = heapsize;
+            while( p!=0 )
+            {
+                parent = (p-1)/2;
+                if( (double)(heap[p,0])>(double)(heap[parent,0]) )
+                {
+                    for(i=0; i<=heapwidth-1; i++)
+                    {
+                        t = heap[p,i];
+                        heap[p,i] = heap[parent,i];
+                        heap[parent,i] = t;
+                    }
+                    p = parent;
+                }
+                else
+                {
+                    break;
+                }
+            }
+        }
+
+
+        private static void mheapresize(ref double[,] heap,
+            ref int heapsize,
+            int newheapsize,
+            int heapwidth)
+        {
+            double[,] tmp = new double[0,0];
+            int i = 0;
+            int i_ = 0;
+
+            tmp = new double[heapsize, heapwidth];
+            for(i=0; i<=heapsize-1; i++)
+            {
+                for(i_=0; i_<=heapwidth-1;i_++)
+                {
+                    tmp[i,i_] = heap[i,i_];
+                }
+            }
+            heap = new double[newheapsize, heapwidth];
+            for(i=0; i<=heapsize-1; i++)
+            {
+                for(i_=0; i_<=heapwidth-1;i_++)
+                {
+                    heap[i,i_] = tmp[i,i_];
+                }
+            }
+            heapsize = newheapsize;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bdss.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bdss.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bdss.cs	(revision 2645)
@@ -0,0 +1,1508 @@
+/*************************************************************************
+Copyright 2008 by Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class bdss
+    {
+        public struct cvreport
+        {
+            public double relclserror;
+            public double avgce;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+        };
+
+
+
+
+        /*************************************************************************
+        This set of routines (DSErrAllocate, DSErrAccumulate, DSErrFinish)
+        calculates different error functions (classification error, cross-entropy,
+        rms, avg, avg.rel errors).
+
+        1. DSErrAllocate prepares buffer.
+        2. DSErrAccumulate accumulates individual errors:
+            * Y contains predicted output (posterior probabilities for classification)
+            * DesiredY contains desired output (class number for classification)
+        3. DSErrFinish outputs results:
+           * Buf[0] contains relative classification error (zero for regression tasks)
+           * Buf[1] contains avg. cross-entropy (zero for regression tasks)
+           * Buf[2] contains rms error (regression, classification)
+           * Buf[3] contains average error (regression, classification)
+           * Buf[4] contains average relative error (regression, classification)
+           
+        NOTES(1):
+            "NClasses>0" means that we have classification task.
+            "NClasses<0" means regression task with -NClasses real outputs.
+
+        NOTES(2):
+            rms. avg, avg.rel errors for classification tasks are interpreted as
+            errors in posterior probabilities with respect to probabilities given
+            by training/test set.
+
+          -- ALGLIB --
+             Copyright 11.01.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dserrallocate(int nclasses,
+            ref double[] buf)
+        {
+            buf = new double[7+1];
+            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.
+
+          -- ALGLIB --
+             Copyright 11.01.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dserraccumulate(ref double[] buf,
+            ref double[] y,
+            ref double[] desiredy)
+        {
+            int nclasses = 0;
+            int nout = 0;
+            int offs = 0;
+            int mmax = 0;
+            int rmax = 0;
+            int j = 0;
+            double v = 0;
+            double ev = 0;
+
+            offs = 5;
+            nclasses = (int)Math.Round(buf[offs]);
+            if( nclasses>0 )
+            {
+                
+                //
+                // Classification
+                //
+                rmax = (int)Math.Round(desiredy[0]);
+                mmax = 0;
+                for(j=1; j<=nclasses-1; j++)
+                {
+                    if( (double)(y[j])>(double)(y[mmax]) )
+                    {
+                        mmax = j;
+                    }
+                }
+                if( mmax!=rmax )
+                {
+                    buf[0] = buf[0]+1;
+                }
+                if( (double)(y[rmax])>(double)(0) )
+                {
+                    buf[1] = buf[1]-Math.Log(y[rmax]);
+                }
+                else
+                {
+                    buf[1] = buf[1]+Math.Log(AP.Math.MaxRealNumber);
+                }
+                for(j=0; j<=nclasses-1; j++)
+                {
+                    v = y[j];
+                    if( j==rmax )
+                    {
+                        ev = 1;
+                    }
+                    else
+                    {
+                        ev = 0;
+                    }
+                    buf[2] = buf[2]+AP.Math.Sqr(v-ev);
+                    buf[3] = buf[3]+Math.Abs(v-ev);
+                    if( (double)(ev)!=(double)(0) )
+                    {
+                        buf[4] = buf[4]+Math.Abs((v-ev)/ev);
+                        buf[offs+2] = buf[offs+2]+1;
+                    }
+                }
+                buf[offs+1] = buf[offs+1]+1;
+            }
+            else
+            {
+                
+                //
+                // Regression
+                //
+                nout = -nclasses;
+                rmax = 0;
+                for(j=1; j<=nout-1; j++)
+                {
+                    if( (double)(desiredy[j])>(double)(desiredy[rmax]) )
+                    {
+                        rmax = j;
+                    }
+                }
+                mmax = 0;
+                for(j=1; j<=nout-1; j++)
+                {
+                    if( (double)(y[j])>(double)(y[mmax]) )
+                    {
+                        mmax = j;
+                    }
+                }
+                if( mmax!=rmax )
+                {
+                    buf[0] = buf[0]+1;
+                }
+                for(j=0; j<=nout-1; j++)
+                {
+                    v = y[j];
+                    ev = desiredy[j];
+                    buf[2] = buf[2]+AP.Math.Sqr(v-ev);
+                    buf[3] = buf[3]+Math.Abs(v-ev);
+                    if( (double)(ev)!=(double)(0) )
+                    {
+                        buf[4] = buf[4]+Math.Abs((v-ev)/ev);
+                        buf[offs+2] = buf[offs+2]+1;
+                    }
+                }
+                buf[offs+1] = buf[offs+1]+1;
+            }
+        }
+
+
+        /*************************************************************************
+        See DSErrAllocate for comments on this routine.
+
+          -- ALGLIB --
+             Copyright 11.01.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dserrfinish(ref double[] buf)
+        {
+            int nout = 0;
+            int offs = 0;
+
+            offs = 5;
+            nout = Math.Abs((int)Math.Round(buf[offs]));
+            if( (double)(buf[offs+1])!=(double)(0) )
+            {
+                buf[0] = buf[0]/buf[offs+1];
+                buf[1] = buf[1]/buf[offs+1];
+                buf[2] = Math.Sqrt(buf[2]/(nout*buf[offs+1]));
+                buf[3] = buf[3]/(nout*buf[offs+1]);
+            }
+            if( (double)(buf[offs+2])!=(double)(0) )
+            {
+                buf[4] = buf[4]/buf[offs+2];
+            }
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 19.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dsnormalize(ref double[,] xy,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref double[] means,
+            ref double[] sigmas)
+        {
+            int i = 0;
+            int j = 0;
+            double[] tmp = new double[0];
+            double mean = 0;
+            double variance = 0;
+            double skewness = 0;
+            double kurtosis = 0;
+            int i_ = 0;
+
+            
+            //
+            // Test parameters
+            //
+            if( npoints<=0 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            
+            //
+            // Standartization
+            //
+            means = new double[nvars-1+1];
+            sigmas = new double[nvars-1+1];
+            tmp = new double[npoints-1+1];
+            for(j=0; j<=nvars-1; j++)
+            {
+                for(i_=0; i_<=npoints-1;i_++)
+                {
+                    tmp[i_] = xy[i_,j];
+                }
+                descriptivestatistics.calculatemoments(ref tmp, npoints, ref mean, ref variance, ref skewness, ref kurtosis);
+                means[j] = mean;
+                sigmas[j] = Math.Sqrt(variance);
+                if( (double)(sigmas[j])==(double)(0) )
+                {
+                    sigmas[j] = 1;
+                }
+                for(i=0; i<=npoints-1; i++)
+                {
+                    xy[i,j] = (xy[i,j]-means[j])/sigmas[j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 19.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dsnormalizec(ref double[,] xy,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref double[] means,
+            ref double[] sigmas)
+        {
+            int i = 0;
+            int j = 0;
+            double[] tmp = new double[0];
+            double mean = 0;
+            double variance = 0;
+            double skewness = 0;
+            double kurtosis = 0;
+            int i_ = 0;
+
+            
+            //
+            // Test parameters
+            //
+            if( npoints<=0 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            
+            //
+            // Standartization
+            //
+            means = new double[nvars-1+1];
+            sigmas = new double[nvars-1+1];
+            tmp = new double[npoints-1+1];
+            for(j=0; j<=nvars-1; j++)
+            {
+                for(i_=0; i_<=npoints-1;i_++)
+                {
+                    tmp[i_] = xy[i_,j];
+                }
+                descriptivestatistics.calculatemoments(ref tmp, npoints, ref mean, ref variance, ref skewness, ref kurtosis);
+                means[j] = mean;
+                sigmas[j] = Math.Sqrt(variance);
+                if( (double)(sigmas[j])==(double)(0) )
+                {
+                    sigmas[j] = 1;
+                }
+            }
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 19.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double dsgetmeanmindistance(ref double[,] xy,
+            int npoints,
+            int nvars)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double[] tmp = new double[0];
+            double[] tmp2 = new double[0];
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            // Test parameters
+            //
+            if( npoints<=0 | nvars<1 )
+            {
+                result = 0;
+                return result;
+            }
+            
+            //
+            // Process
+            //
+            tmp = new double[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                tmp[i] = AP.Math.MaxRealNumber;
+            }
+            tmp2 = new double[nvars-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(j=i+1; j<=npoints-1; j++)
+                {
+                    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_];
+                    }
+                    v = Math.Sqrt(v);
+                    tmp[i] = Math.Min(tmp[i], v);
+                    tmp[j] = Math.Min(tmp[j], v);
+                }
+            }
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                result = result+tmp[i]/npoints;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 19.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dstie(ref double[] a,
+            int n,
+            ref int[] ties,
+            ref int tiecount,
+            ref int[] p1,
+            ref int[] p2)
+        {
+            int i = 0;
+            int k = 0;
+            int[] tmp = new int[0];
+
+            
+            //
+            // Special case
+            //
+            if( n<=0 )
+            {
+                tiecount = 0;
+                return;
+            }
+            
+            //
+            // Sort A
+            //
+            tsort.tagsort(ref a, n, ref p1, ref p2);
+            
+            //
+            // Process ties
+            //
+            tiecount = 1;
+            for(i=1; i<=n-1; i++)
+            {
+                if( (double)(a[i])!=(double)(a[i-1]) )
+                {
+                    tiecount = tiecount+1;
+                }
+            }
+            ties = new int[tiecount+1];
+            ties[0] = 0;
+            k = 1;
+            for(i=1; i<=n-1; i++)
+            {
+                if( (double)(a[i])!=(double)(a[i-1]) )
+                {
+                    ties[k] = i;
+                    k = k+1;
+                }
+            }
+            ties[tiecount] = n;
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 11.12.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dstiefasti(ref double[] a,
+            ref int[] b,
+            int n,
+            ref int[] ties,
+            ref int tiecount)
+        {
+            int i = 0;
+            int k = 0;
+            int[] tmp = new int[0];
+
+            
+            //
+            // Special case
+            //
+            if( n<=0 )
+            {
+                tiecount = 0;
+                return;
+            }
+            
+            //
+            // Sort A
+            //
+            tsort.tagsortfasti(ref a, ref b, n);
+            
+            //
+            // Process ties
+            //
+            ties[0] = 0;
+            k = 1;
+            for(i=1; i<=n-1; i++)
+            {
+                if( (double)(a[i])!=(double)(a[i-1]) )
+                {
+                    ties[k] = i;
+                    k = k+1;
+                }
+            }
+            ties[k] = n;
+            tiecount = k;
+        }
+
+
+        /*************************************************************************
+        Optimal partition, internal subroutine.
+
+          -- ALGLIB --
+             Copyright 22.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dsoptimalsplit2(double[] a,
+            int[] c,
+            int n,
+            ref int info,
+            ref double threshold,
+            ref double pal,
+            ref double pbl,
+            ref double par,
+            ref double pbr,
+            ref double cve)
+        {
+            int i = 0;
+            int t = 0;
+            double s = 0;
+            double pea = 0;
+            double peb = 0;
+            int[] ties = new int[0];
+            int tiecount = 0;
+            int[] p1 = new int[0];
+            int[] p2 = new int[0];
+            double v1 = 0;
+            double v2 = 0;
+            int k = 0;
+            int koptimal = 0;
+            double pak = 0;
+            double pbk = 0;
+            double cvoptimal = 0;
+            double cv = 0;
+
+            a = (double[])a.Clone();
+            c = (int[])c.Clone();
+
+            
+            //
+            // Test for errors in inputs
+            //
+            if( n<=0 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                if( c[i]!=0 & c[i]!=1 )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Tie
+            //
+            dstie(ref a, n, ref ties, ref tiecount, ref p1, ref p2);
+            for(i=0; i<=n-1; i++)
+            {
+                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++)
+            {
+                if( c[i]==0 )
+                {
+                    par = par+1;
+                }
+                if( c[i]==1 )
+                {
+                    pbr = pbr+1;
+                }
+            }
+            koptimal = -1;
+            cvoptimal = AP.Math.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++)
+                {
+                    if( c[i]==0 )
+                    {
+                        pak = pak+1;
+                    }
+                    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( (double)(cv)<(double)(cvoptimal) )
+                {
+                    cvoptimal = cv;
+                    koptimal = k;
+                }
+                
+                //
+                // update
+                //
+                pal = pal+pak;
+                pbl = pbl+pbk;
+                par = par-pak;
+                pbr = pbr-pbk;
+            }
+            cve = cvoptimal;
+            threshold = 0.5*(a[ties[koptimal]]+a[ties[koptimal+1]]);
+            pal = 0;
+            pbl = 0;
+            par = 0;
+            pbr = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(a[i])<(double)(threshold) )
+                {
+                    if( c[i]==0 )
+                    {
+                        pal = pal+1;
+                    }
+                    else
+                    {
+                        pbl = pbl+1;
+                    }
+                }
+                else
+                {
+                    if( c[i]==0 )
+                    {
+                        par = par+1;
+                    }
+                    else
+                    {
+                        pbr = pbr+1;
+                    }
+                }
+            }
+            s = pal+pbl;
+            pal = pal/s;
+            pbl = pbl/s;
+            s = par+pbr;
+            par = par/s;
+            pbr = pbr/s;
+        }
+
+
+        /*************************************************************************
+        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)
+            
+        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
+
+          -- ALGLIB --
+             Copyright 11.12.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dsoptimalsplit2fast(ref double[] a,
+            ref int[] c,
+            ref int[] tiesbuf,
+            ref int[] cntbuf,
+            int n,
+            int nc,
+            double alpha,
+            ref int info,
+            ref double threshold,
+            ref double rms,
+            ref double cvrms)
+        {
+            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;
+
+            
+            //
+            // Test for errors in inputs
+            //
+            if( n<=0 | nc<2 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                if( c[i]<0 | c[i]>=nc )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Tie
+            //
+            dstiefasti(ref a, ref c, n, ref tiesbuf, ref tiecount);
+            
+            //
+            // 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;
+            }
+            koptimal = -1;
+            threshold = a[n-1];
+            cbest = AP.Math.MaxRealNumber;
+            sl = 0;
+            sr = n;
+            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*AP.Math.Sqr(w/sl-1);
+                    v = v+(sl-w)*AP.Math.Sqr(w/sl);
+                    w = cntbuf[nc+i];
+                    v = v+w*AP.Math.Sqr(w/sr-1);
+                    v = v+(sr-w)*AP.Math.Sqr(w/sr);
+                }
+                v = Math.Sqrt(v/(nc*n));
+                
+                //
+                // Compare with best
+                //
+                x = (double)(2*sl)/((double)(sl+sr))-1;
+                cc = v*(1-alpha+alpha*AP.Math.Sqr(x));
+                if( (double)(cc)<(double)(cbest) )
+                {
+                    
+                    //
+                    // store split
+                    //
+                    rms = v;
+                    koptimal = k;
+                    cbest = cc;
+                    
+                    //
+                    // calculate CVRMS error
+                    //
+                    cvrms = 0;
+                    for(i=0; i<=nc-1; i++)
+                    {
+                        if( sl>1 )
+                        {
+                            w = cntbuf[i];
+                            cvrms = cvrms+w*AP.Math.Sqr((w-1)/(sl-1)-1);
+                            cvrms = cvrms+(sl-w)*AP.Math.Sqr(w/(sl-1));
+                        }
+                        else
+                        {
+                            w = cntbuf[i];
+                            cvrms = cvrms+w*AP.Math.Sqr((double)(1)/(double)(nc)-1);
+                            cvrms = cvrms+(sl-w)*AP.Math.Sqr((double)(1)/(double)(nc));
+                        }
+                        if( sr>1 )
+                        {
+                            w = cntbuf[nc+i];
+                            cvrms = cvrms+w*AP.Math.Sqr((w-1)/(sr-1)-1);
+                            cvrms = cvrms+(sr-w)*AP.Math.Sqr(w/(sr-1));
+                        }
+                        else
+                        {
+                            w = cntbuf[nc+i];
+                            cvrms = cvrms+w*AP.Math.Sqr((double)(1)/(double)(nc)-1);
+                            cvrms = cvrms+(sr-w)*AP.Math.Sqr((double)(1)/(double)(nc));
+                        }
+                    }
+                    cvrms = Math.Sqrt(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]]);
+            if( (double)(threshold)<=(double)(a[tiesbuf[koptimal]]) )
+            {
+                threshold = a[tiesbuf[koptimal+1]];
+            }
+        }
+
+
+        /*************************************************************************
+        Automatic non-optimal discretization, internal subroutine.
+
+          -- ALGLIB --
+             Copyright 22.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dssplitk(double[] a,
+            int[] c,
+            int n,
+            int nc,
+            int kmax,
+            ref int info,
+            ref double[] thresholds,
+            ref int ni,
+            ref double cve)
+        {
+            int i = 0;
+            int j = 0;
+            int j1 = 0;
+            int k = 0;
+            int[] ties = new int[0];
+            int tiecount = 0;
+            int[] p1 = new int[0];
+            int[] p2 = new int[0];
+            int[] cnt = new int[0];
+            double v2 = 0;
+            int bestk = 0;
+            double bestcve = 0;
+            int[] bestsizes = new int[0];
+            double curcve = 0;
+            int[] cursizes = new int[0];
+
+            a = (double[])a.Clone();
+            c = (int[])c.Clone();
+
+            
+            //
+            // Test for errors in inputs
+            //
+            if( n<=0 | nc<2 | kmax<2 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                if( c[i]<0 | c[i]>=nc )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Tie
+            //
+            dstie(ref a, n, ref ties, ref tiecount, ref p1, ref p2);
+            for(i=0; i<=n-1; i++)
+            {
+                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 = Math.Min(kmax, tiecount);
+            bestsizes = new int[kmax-1+1];
+            cursizes = new int[kmax-1+1];
+            cnt = new int[nc-1+1];
+            
+            //
+            // General case:
+            // 1. prepare "weak" solution (two subintervals, divided at median)
+            //
+            v2 = AP.Math.MaxRealNumber;
+            j = -1;
+            for(i=1; i<=tiecount-1; i++)
+            {
+                if( (double)(Math.Abs(ties[i]-0.5*(n-1)))<(double)(v2) )
+                {
+                    v2 = Math.Abs(ties[i]-0.5*n);
+                    j = i;
+                }
+            }
+            System.Diagnostics.Debug.Assert(j>0, "DSSplitK: internal error #1!");
+            bestk = 2;
+            bestsizes[0] = ties[j];
+            bestsizes[1] = n-j;
+            bestcve = 0;
+            for(i=0; i<=nc-1; i++)
+            {
+                cnt[i] = 0;
+            }
+            for(i=0; i<=j-1; i++)
+            {
+                tieaddc(ref c, ref ties, i, nc, ref cnt);
+            }
+            bestcve = bestcve+getcv(ref cnt, nc);
+            for(i=0; i<=nc-1; i++)
+            {
+                cnt[i] = 0;
+            }
+            for(i=j; i<=tiecount-1; i++)
+            {
+                tieaddc(ref c, ref ties, i, nc, ref cnt);
+            }
+            bestcve = bestcve+getcv(ref 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;
+                }
+                i = 0;
+                j = 0;
+                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( (double)(Math.Abs(cursizes[i]+ties[j+1]-ties[j]-(double)(n)/(double)(k)))<(double)(Math.Abs(cursizes[i]-(double)(n)/(double)(k))) )
+                    {
+                        cursizes[i] = cursizes[i]+ties[j+1]-ties[j];
+                        j = j+1;
+                    }
+                    else
+                    {
+                        i = i+1;
+                    }
+                }
+                System.Diagnostics.Debug.Assert(cursizes[k-1]!=0 & j==tiecount, "DSSplitK: internal error #1");
+                
+                //
+                // Calculate CVE
+                //
+                curcve = 0;
+                j = 0;
+                for(i=0; i<=k-1; i++)
+                {
+                    for(j1=0; j1<=nc-1; j1++)
+                    {
+                        cnt[j1] = 0;
+                    }
+                    for(j1=j; j1<=j+cursizes[i]-1; j1++)
+                    {
+                        cnt[c[j1]] = cnt[c[j1]]+1;
+                    }
+                    curcve = curcve+getcv(ref cnt, nc);
+                    j = j+cursizes[i];
+                }
+                
+                //
+                // Choose best variant
+                //
+                if( (double)(curcve)<(double)(bestcve) )
+                {
+                    for(i=0; i<=k-1; i++)
+                    {
+                        bestsizes[i] = cursizes[i];
+                    }
+                    bestcve = curcve;
+                    bestk = k;
+                }
+            }
+            
+            //
+            // Transform from sizes to thresholds
+            //
+            cve = bestcve;
+            ni = bestk;
+            thresholds = new double[ni-2+1];
+            j = bestsizes[0];
+            for(i=1; i<=bestk-1; i++)
+            {
+                thresholds[i-1] = 0.5*(a[j-1]+a[j]);
+                j = j+bestsizes[i];
+            }
+        }
+
+
+        /*************************************************************************
+        Automatic optimal discretization, internal subroutine.
+
+          -- ALGLIB --
+             Copyright 22.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dsoptimalsplitk(double[] a,
+            int[] c,
+            int n,
+            int nc,
+            int kmax,
+            ref int info,
+            ref double[] thresholds,
+            ref int ni,
+            ref double cve)
+        {
+            int i = 0;
+            int j = 0;
+            int s = 0;
+            int jl = 0;
+            int jr = 0;
+            double v1 = 0;
+            double v2 = 0;
+            double v3 = 0;
+            double v4 = 0;
+            int[] ties = new int[0];
+            int tiecount = 0;
+            int[] p1 = new int[0];
+            int[] p2 = new int[0];
+            double cvtemp = 0;
+            int[] cnt = new int[0];
+            int[] cnt2 = new int[0];
+            double[,] cv = new double[0,0];
+            int[,] splits = new int[0,0];
+            int k = 0;
+            int koptimal = 0;
+            double cvoptimal = 0;
+
+            a = (double[])a.Clone();
+            c = (int[])c.Clone();
+
+            
+            //
+            // Test for errors in inputs
+            //
+            if( n<=0 | nc<2 | kmax<2 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                if( c[i]<0 | c[i]>=nc )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Tie
+            //
+            dstie(ref a, n, ref ties, ref tiecount, ref p1, ref p2);
+            for(i=0; i<=n-1; i++)
+            {
+                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 = Math.Min(kmax, tiecount);
+            cv = new double[kmax-1+1, tiecount-1+1];
+            splits = new int[kmax-1+1, tiecount-1+1];
+            cnt = new int[nc-1+1];
+            cnt2 = new int[nc-1+1];
+            for(j=0; j<=nc-1; j++)
+            {
+                cnt[j] = 0;
+            }
+            for(j=0; j<=tiecount-1; j++)
+            {
+                tieaddc(ref c, ref ties, j, nc, ref cnt);
+                splits[0,j] = 0;
+                cv[0,j] = getcv(ref 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(ref c, ref ties, j, nc, ref cnt);
+                    
+                    //
+                    // Search for optimal split point S in [K..J]
+                    //
+                    for(i=0; i<=nc-1; i++)
+                    {
+                        cnt2[i] = cnt[i];
+                    }
+                    cv[k,j] = cv[k-1,j-1]+getcv(ref cnt2, nc);
+                    splits[k,j] = j;
+                    for(s=k+1; s<=j; s++)
+                    {
+                        
+                        //
+                        // Update Cnt2 - let it contain classes of ties from S-th to J-th
+                        //
+                        tiesubc(ref c, ref ties, s-1, nc, ref cnt2);
+                        
+                        //
+                        // Calculate CVE
+                        //
+                        cvtemp = cv[k-1,s-1]+getcv(ref cnt2, nc);
+                        if( (double)(cvtemp)<(double)(cv[k,j]) )
+                        {
+                            cv[k,j] = cvtemp;
+                            splits[k,j] = s;
+                        }
+                    }
+                }
+            }
+            
+            //
+            // Choose best partition, output result
+            //
+            koptimal = -1;
+            cvoptimal = AP.Math.MaxRealNumber;
+            for(k=0; k<=kmax-1; k++)
+            {
+                if( (double)(cv[k,tiecount-1])<(double)(cvoptimal) )
+                {
+                    cvoptimal = cv[k,tiecount-1];
+                    koptimal = k;
+                }
+            }
+            System.Diagnostics.Debug.Assert(koptimal>=0, "DSOptimalSplitK: internal error #1!");
+            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 = AP.Math.MaxRealNumber;
+                j = -1;
+                for(i=1; i<=tiecount-1; i++)
+                {
+                    if( (double)(Math.Abs(ties[i]-0.5*(n-1)))<(double)(v2) )
+                    {
+                        v2 = Math.Abs(ties[i]-0.5*(n-1));
+                        j = i;
+                    }
+                }
+                System.Diagnostics.Debug.Assert(j>0, "DSOptimalSplitK: internal error #2!");
+                thresholds = new double[0+1];
+                thresholds[0] = 0.5*(a[ties[j-1]]+a[ties[j]]);
+                ni = 2;
+                cve = 0;
+                for(i=0; i<=nc-1; i++)
+                {
+                    cnt[i] = 0;
+                }
+                for(i=0; i<=j-1; i++)
+                {
+                    tieaddc(ref c, ref ties, i, nc, ref cnt);
+                }
+                cve = cve+getcv(ref cnt, nc);
+                for(i=0; i<=nc-1; i++)
+                {
+                    cnt[i] = 0;
+                }
+                for(i=j; i<=tiecount-1; i++)
+                {
+                    tieaddc(ref c, ref ties, i, nc, ref cnt);
+                }
+                cve = cve+getcv(ref cnt, nc);
+            }
+            else
+            {
+                
+                //
+                // General case: 2 or more intervals
+                //
+                thresholds = new double[koptimal-1+1];
+                ni = koptimal+1;
+                cve = cv[koptimal,tiecount-1];
+                jl = splits[koptimal,tiecount-1];
+                jr = tiecount-1;
+                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];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 11.01.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void dskfoldsplit(ref double[,] xy,
+            int npoints,
+            int nclasses,
+            int foldscount,
+            bool stratifiedsplits,
+            ref int[] folds)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+
+            
+            //
+            // test parameters
+            //
+            System.Diagnostics.Debug.Assert(npoints>0, "DSKFoldSplit: wrong NPoints!");
+            System.Diagnostics.Debug.Assert(nclasses>1 | nclasses<0, "DSKFoldSplit: wrong NClasses!");
+            System.Diagnostics.Debug.Assert(foldscount>=2 & foldscount<=npoints, "DSKFoldSplit: wrong FoldsCount!");
+            System.Diagnostics.Debug.Assert(!stratifiedsplits, "DSKFoldSplit: stratified splits are not supported!");
+            
+            //
+            // Folds
+            //
+            folds = new int[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                folds[i] = i*foldscount/npoints;
+            }
+            for(i=0; i<=npoints-2; i++)
+            {
+                j = i+AP.Math.RandomInteger(npoints-i);
+                if( j!=i )
+                {
+                    k = folds[i];
+                    folds[i] = folds[j];
+                    folds[j] = k;
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal function
+        *************************************************************************/
+        private static double xlny(double x,
+            double y)
+        {
+            double result = 0;
+
+            if( (double)(x)==(double)(0) )
+            {
+                result = 0;
+            }
+            else
+            {
+                result = x*Math.Log(y);
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal function,
+        returns number of samples of class I in Cnt[I]
+        *************************************************************************/
+        private static double getcv(ref int[] cnt,
+            int nc)
+        {
+            double result = 0;
+            int i = 0;
+            double s = 0;
+
+            s = 0;
+            for(i=0; i<=nc-1; i++)
+            {
+                s = s+cnt[i];
+            }
+            result = 0;
+            for(i=0; i<=nc-1; i++)
+            {
+                result = result-xlny(cnt[i], cnt[i]/(s+nc-1));
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal function, adds number of samples of class I in tie NTie to Cnt[I]
+        *************************************************************************/
+        private static void tieaddc(ref int[] c,
+            ref int[] ties,
+            int ntie,
+            int nc,
+            ref int[] cnt)
+        {
+            int i = 0;
+
+            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]
+        *************************************************************************/
+        private static void tiesubc(ref int[] c,
+            ref int[] ties,
+            int ntie,
+            int nc,
+            ref int[] cnt)
+        {
+            int i = 0;
+
+            for(i=ties[ntie]; i<=ties[ntie+1]-1; i++)
+            {
+                cnt[c[i]] = cnt[c[i]]-1;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal function,
+        returns number of samples of class I in Cnt[I]
+        *************************************************************************/
+        private static void tiegetc(ref int[] c,
+            ref int[] ties,
+            int ntie,
+            int nc,
+            ref int[] cnt)
+        {
+            int i = 0;
+
+            for(i=0; i<=nc-1; i++)
+            {
+                cnt[i] = 0;
+            }
+            for(i=ties[ntie]; i<=ties[ntie+1]-1; i++)
+            {
+                cnt[c[i]] = cnt[c[i]]+1;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bdsvd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bdsvd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bdsvd.cs	(revision 2645)
@@ -0,0 +1,1391 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class bdsvd
+    {
+        /*************************************************************************
+        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.
+        *************************************************************************/
+        public static bool rmatrixbdsvd(ref double[] d,
+            double[] e,
+            int n,
+            bool isupper,
+            bool isfractionalaccuracyrequired,
+            ref double[,] u,
+            int nru,
+            ref double[,] c,
+            int ncc,
+            ref double[,] vt,
+            int ncvt)
+        {
+            bool result = new bool();
+            double[] d1 = new double[0];
+            double[] e1 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            e = (double[])e.Clone();
+
+            d1 = new double[n+1];
+            i1_ = (0) - (1);
+            for(i_=1; i_<=n;i_++)
+            {
+                d1[i_] = d[i_+i1_];
+            }
+            if( n>1 )
+            {
+                e1 = new double[n-1+1];
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n-1;i_++)
+                {
+                    e1[i_] = e[i_+i1_];
+                }
+            }
+            result = bidiagonalsvddecompositioninternal(ref d1, e1, n, isupper, isfractionalaccuracyrequired, ref u, 0, nru, ref c, 0, ncc, ref vt, 0, ncvt);
+            i1_ = (1) - (0);
+            for(i_=0; i_<=n-1;i_++)
+            {
+                d[i_] = d1[i_+i1_];
+            }
+            return result;
+        }
+
+
+        public static bool bidiagonalsvddecomposition(ref double[] d,
+            double[] e,
+            int n,
+            bool isupper,
+            bool isfractionalaccuracyrequired,
+            ref double[,] u,
+            int nru,
+            ref double[,] c,
+            int ncc,
+            ref double[,] vt,
+            int ncvt)
+        {
+            bool result = new bool();
+
+            e = (double[])e.Clone();
+
+            result = bidiagonalsvddecompositioninternal(ref d, e, n, isupper, isfractionalaccuracyrequired, ref u, 1, nru, ref c, 1, ncc, ref vt, 1, ncvt);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal working subroutine for bidiagonal decomposition
+        *************************************************************************/
+        private static bool bidiagonalsvddecompositioninternal(ref double[] d,
+            double[] e,
+            int n,
+            bool isupper,
+            bool isfractionalaccuracyrequired,
+            ref double[,] u,
+            int ustart,
+            int nru,
+            ref double[,] c,
+            int cstart,
+            int ncc,
+            ref double[,] vt,
+            int vstart,
+            int ncvt)
+        {
+            bool result = new bool();
+            int i = 0;
+            int idir = 0;
+            int isub = 0;
+            int iter = 0;
+            int j = 0;
+            int ll = 0;
+            int lll = 0;
+            int m = 0;
+            int maxit = 0;
+            int oldll = 0;
+            int oldm = 0;
+            double abse = 0;
+            double abss = 0;
+            double cosl = 0;
+            double cosr = 0;
+            double cs = 0;
+            double eps = 0;
+            double f = 0;
+            double g = 0;
+            double h = 0;
+            double mu = 0;
+            double oldcs = 0;
+            double oldsn = 0;
+            double r = 0;
+            double shift = 0;
+            double sigmn = 0;
+            double sigmx = 0;
+            double sinl = 0;
+            double sinr = 0;
+            double sll = 0;
+            double smax = 0;
+            double smin = 0;
+            double sminl = 0;
+            double sminlo = 0;
+            double sminoa = 0;
+            double sn = 0;
+            double thresh = 0;
+            double tol = 0;
+            double tolmul = 0;
+            double unfl = 0;
+            double[] work0 = new double[0];
+            double[] work1 = new double[0];
+            double[] work2 = new double[0];
+            double[] work3 = new double[0];
+            int maxitr = 0;
+            bool matrixsplitflag = new bool();
+            bool iterflag = new bool();
+            double[] utemp = new double[0];
+            double[] vttemp = new double[0];
+            double[] ctemp = new double[0];
+            double[] etemp = new double[0];
+            bool rightside = new bool();
+            bool fwddir = new bool();
+            double tmp = 0;
+            int mm1 = 0;
+            int mm0 = 0;
+            bool bchangedir = new bool();
+            int uend = 0;
+            int cend = 0;
+            int vend = 0;
+            int i_ = 0;
+
+            e = (double[])e.Clone();
+
+            result = true;
+            if( n==0 )
+            {
+                return result;
+            }
+            if( n==1 )
+            {
+                if( (double)(d[1])<(double)(0) )
+                {
+                    d[1] = -d[1];
+                    if( ncvt>0 )
+                    {
+                        for(i_=vstart; i_<=vstart+ncvt-1;i_++)
+                        {
+                            vt[vstart,i_] = -1*vt[vstart,i_];
+                        }
+                    }
+                }
+                return result;
+            }
+            
+            //
+            // init
+            //
+            work0 = new double[n-1+1];
+            work1 = new double[n-1+1];
+            work2 = new double[n-1+1];
+            work3 = new double[n-1+1];
+            uend = ustart+Math.Max(nru-1, 0);
+            vend = vstart+Math.Max(ncvt-1, 0);
+            cend = cstart+Math.Max(ncc-1, 0);
+            utemp = new double[uend+1];
+            vttemp = new double[vend+1];
+            ctemp = new double[cend+1];
+            maxitr = 12;
+            rightside = true;
+            fwddir = true;
+            
+            //
+            // resize E from N-1 to N
+            //
+            etemp = new double[n+1];
+            for(i=1; i<=n-1; i++)
+            {
+                etemp[i] = e[i];
+            }
+            e = new double[n+1];
+            for(i=1; i<=n-1; i++)
+            {
+                e[i] = etemp[i];
+            }
+            e[n] = 0;
+            idir = 0;
+            
+            //
+            // Get machine constants
+            //
+            eps = AP.Math.MachineEpsilon;
+            unfl = AP.Math.MinRealNumber;
+            
+            //
+            // If matrix lower bidiagonal, rotate to be upper bidiagonal
+            // by applying Givens rotations on the left
+            //
+            if( !isupper )
+            {
+                for(i=1; i<=n-1; i++)
+                {
+                    rotations.generaterotation(d[i], e[i], ref cs, ref sn, ref r);
+                    d[i] = r;
+                    e[i] = sn*d[i+1];
+                    d[i+1] = cs*d[i+1];
+                    work0[i] = cs;
+                    work1[i] = sn;
+                }
+                
+                //
+                // Update singular vectors if desired
+                //
+                if( nru>0 )
+                {
+                    rotations.applyrotationsfromtheright(fwddir, ustart, uend, 1+ustart-1, n+ustart-1, ref work0, ref work1, ref u, ref utemp);
+                }
+                if( ncc>0 )
+                {
+                    rotations.applyrotationsfromtheleft(fwddir, 1+cstart-1, n+cstart-1, cstart, cend, ref work0, ref work1, ref c, ref 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 = Math.Max(10, Math.Min(100, Math.Pow(eps, -0.125)));
+            tol = tolmul*eps;
+            if( !isfractionalaccuracyrequired )
+            {
+                tol = -tol;
+            }
+            
+            //
+            // Compute approximate maximum, minimum singular values
+            //
+            smax = 0;
+            for(i=1; i<=n; i++)
+            {
+                smax = Math.Max(smax, Math.Abs(d[i]));
+            }
+            for(i=1; i<=n-1; i++)
+            {
+                smax = Math.Max(smax, Math.Abs(e[i]));
+            }
+            sminl = 0;
+            if( (double)(tol)>=(double)(0) )
+            {
+                
+                //
+                // Relative accuracy desired
+                //
+                sminoa = Math.Abs(d[1]);
+                if( (double)(sminoa)!=(double)(0) )
+                {
+                    mu = sminoa;
+                    for(i=2; i<=n; i++)
+                    {
+                        mu = Math.Abs(d[i])*(mu/(mu+Math.Abs(e[i-1])));
+                        sminoa = Math.Min(sminoa, mu);
+                        if( (double)(sminoa)==(double)(0) )
+                        {
+                            break;
+                        }
+                    }
+                }
+                sminoa = sminoa/Math.Sqrt(n);
+                thresh = Math.Max(tol*sminoa, maxitr*n*n*unfl);
+            }
+            else
+            {
+                
+                //
+                // Absolute accuracy desired
+                //
+                thresh = Math.Max(Math.Abs(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;
+                }
+                if( iter>maxit )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Find diagonal block of matrix to work on
+                //
+                if( (double)(tol)<(double)(0) & (double)(Math.Abs(d[m]))<=(double)(thresh) )
+                {
+                    d[m] = 0;
+                }
+                smax = Math.Abs(d[m]);
+                smin = smax;
+                matrixsplitflag = false;
+                for(lll=1; lll<=m-1; lll++)
+                {
+                    ll = m-lll;
+                    abss = Math.Abs(d[ll]);
+                    abse = Math.Abs(e[ll]);
+                    if( (double)(tol)<(double)(0) & (double)(abss)<=(double)(thresh) )
+                    {
+                        d[ll] = 0;
+                    }
+                    if( (double)(abse)<=(double)(thresh) )
+                    {
+                        matrixsplitflag = true;
+                        break;
+                    }
+                    smin = Math.Min(smin, abss);
+                    smax = Math.Max(smax, Math.Max(abss, abse));
+                }
+                if( !matrixsplitflag )
+                {
+                    ll = 0;
+                }
+                else
+                {
+                    
+                    //
+                    // Matrix splits since E(LL) = 0
+                    //
+                    e[ll] = 0;
+                    if( ll==m-1 )
+                    {
+                        
+                        //
+                        // Convergence of bottom singular value, return to top of loop
+                        //
+                        m = m-1;
+                        continue;
+                    }
+                }
+                ll = ll+1;
+                
+                //
+                // E(LL) through E(M-1) are nonzero, E(LL-1) is zero
+                //
+                if( ll==m-1 )
+                {
+                    
+                    //
+                    // 2 by 2 block, handle separately
+                    //
+                    svdv2x2(d[m-1], e[m-1], d[m], ref sigmn, ref sigmx, ref sinr, ref cosr, ref sinl, ref 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);
+                        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,i_] = cosr*vt[mm0,i_];
+                        }
+                        for(i_=vstart; i_<=vend;i_++)
+                        {
+                            vt[mm0,i_] = vt[mm0,i_] - sinr*vt[mm1,i_];
+                        }
+                        for(i_=vstart; i_<=vend;i_++)
+                        {
+                            vt[mm1,i_] = vttemp[i_];
+                        }
+                    }
+                    if( nru>0 )
+                    {
+                        mm0 = m+ustart-1;
+                        mm1 = m-1+ustart-1;
+                        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_,mm0] = cosl*u[i_,mm0];
+                        }
+                        for(i_=ustart; i_<=uend;i_++)
+                        {
+                            u[i_,mm0] = u[i_,mm0] - sinl*u[i_,mm1];
+                        }
+                        for(i_=ustart; i_<=uend;i_++)
+                        {
+                            u[i_,mm1] = utemp[i_];
+                        }
+                    }
+                    if( ncc>0 )
+                    {
+                        mm0 = m+cstart-1;
+                        mm1 = m-1+cstart-1;
+                        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,i_] = cosl*c[mm0,i_];
+                        }
+                        for(i_=cstart; i_<=cend;i_++)
+                        {
+                            c[mm0,i_] = c[mm0,i_] - sinl*c[mm1,i_];
+                        }
+                        for(i_=cstart; i_<=cend;i_++)
+                        {
+                            c[mm1,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<OLDLL) then"
+                // fixed thanks to Michael Rolle < m@rolle.name >
+                // Very strange that LAPACK still contains it.
+                //
+                bchangedir = false;
+                if( idir==1 & (double)(Math.Abs(d[ll]))<(double)(1.0E-3*Math.Abs(d[m])) )
+                {
+                    bchangedir = true;
+                }
+                if( idir==2 & (double)(Math.Abs(d[m]))<(double)(1.0E-3*Math.Abs(d[ll])) )
+                {
+                    bchangedir = true;
+                }
+                if( ll!=oldll | m!=oldm | bchangedir )
+                {
+                    if( (double)(Math.Abs(d[ll]))>=(double)(Math.Abs(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( (double)(Math.Abs(e[m-1]))<=(double)(Math.Abs(tol)*Math.Abs(d[m])) | (double)(tol)<(double)(0) & (double)(Math.Abs(e[m-1]))<=(double)(thresh) )
+                    {
+                        e[m-1] = 0;
+                        continue;
+                    }
+                    if( (double)(tol)>=(double)(0) )
+                    {
+                        
+                        //
+                        // If relative accuracy desired,
+                        // apply convergence criterion forward
+                        //
+                        mu = Math.Abs(d[ll]);
+                        sminl = mu;
+                        iterflag = false;
+                        for(lll=ll; lll<=m-1; lll++)
+                        {
+                            if( (double)(Math.Abs(e[lll]))<=(double)(tol*mu) )
+                            {
+                                e[lll] = 0;
+                                iterflag = true;
+                                break;
+                            }
+                            sminlo = sminl;
+                            mu = Math.Abs(d[lll+1])*(mu/(mu+Math.Abs(e[lll])));
+                            sminl = Math.Min(sminl, mu);
+                        }
+                        if( iterflag )
+                        {
+                            continue;
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // Run convergence test in backward direction
+                    // First apply standard test to top of matrix
+                    //
+                    if( (double)(Math.Abs(e[ll]))<=(double)(Math.Abs(tol)*Math.Abs(d[ll])) | (double)(tol)<(double)(0) & (double)(Math.Abs(e[ll]))<=(double)(thresh) )
+                    {
+                        e[ll] = 0;
+                        continue;
+                    }
+                    if( (double)(tol)>=(double)(0) )
+                    {
+                        
+                        //
+                        // If relative accuracy desired,
+                        // apply convergence criterion backward
+                        //
+                        mu = Math.Abs(d[m]);
+                        sminl = mu;
+                        iterflag = false;
+                        for(lll=m-1; lll>=ll; lll--)
+                        {
+                            if( (double)(Math.Abs(e[lll]))<=(double)(tol*mu) )
+                            {
+                                e[lll] = 0;
+                                iterflag = true;
+                                break;
+                            }
+                            sminlo = sminl;
+                            mu = Math.Abs(d[lll])*(mu/(mu+Math.Abs(e[lll])));
+                            sminl = Math.Min(sminl, mu);
+                        }
+                        if( iterflag )
+                        {
+                            continue;
+                        }
+                    }
+                }
+                oldll = ll;
+                oldm = m;
+                
+                //
+                // Compute shift.  First, test if shifting would ruin relative
+                // accuracy, and if so set the shift to zero.
+                //
+                if( (double)(tol)>=(double)(0) & (double)(n*tol*(sminl/smax))<=(double)(Math.Max(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 = Math.Abs(d[ll]);
+                        svd2x2(d[m-1], e[m-1], d[m], ref shift, ref r);
+                    }
+                    else
+                    {
+                        sll = Math.Abs(d[m]);
+                        svd2x2(d[ll], e[ll], d[ll+1], ref shift, ref r);
+                    }
+                    
+                    //
+                    // Test if shift negligible, and if so set to zero
+                    //
+                    if( (double)(sll)>(double)(0) )
+                    {
+                        if( (double)(AP.Math.Sqr(shift/sll))<(double)(eps) )
+                        {
+                            shift = 0;
+                        }
+                    }
+                }
+                
+                //
+                // Increment iteration count
+                //
+                iter = iter+m-ll;
+                
+                //
+                // If SHIFT = 0, do simplified QR iteration
+                //
+                if( (double)(shift)==(double)(0) )
+                {
+                    if( idir==1 )
+                    {
+                        
+                        //
+                        // Chase bulge from top to bottom
+                        // Save cosines and sines for later singular vector updates
+                        //
+                        cs = 1;
+                        oldcs = 1;
+                        for(i=ll; i<=m-1; i++)
+                        {
+                            rotations.generaterotation(d[i]*cs, e[i], ref cs, ref sn, ref r);
+                            if( i>ll )
+                            {
+                                e[i-1] = oldsn*r;
+                            }
+                            rotations.generaterotation(oldcs*r, d[i+1]*sn, ref oldcs, ref oldsn, ref tmp);
+                            d[i] = tmp;
+                            work0[i-ll+1] = cs;
+                            work1[i-ll+1] = sn;
+                            work2[i-ll+1] = oldcs;
+                            work3[i-ll+1] = oldsn;
+                        }
+                        h = d[m]*cs;
+                        d[m] = h*oldcs;
+                        e[m-1] = h*oldsn;
+                        
+                        //
+                        // Update singular vectors
+                        //
+                        if( ncvt>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, ref work0, ref work1, ref vt, ref vttemp);
+                        }
+                        if( nru>0 )
+                        {
+                            rotations.applyrotationsfromtheright(fwddir, ustart, uend, ll+ustart-1, m+ustart-1, ref work2, ref work3, ref u, ref utemp);
+                        }
+                        if( ncc>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, ref work2, ref work3, ref c, ref ctemp);
+                        }
+                        
+                        //
+                        // Test convergence
+                        //
+                        if( (double)(Math.Abs(e[m-1]))<=(double)(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--)
+                        {
+                            rotations.generaterotation(d[i]*cs, e[i-1], ref cs, ref sn, ref r);
+                            if( i<m )
+                            {
+                                e[i] = oldsn*r;
+                            }
+                            rotations.generaterotation(oldcs*r, d[i-1]*sn, ref oldcs, ref oldsn, ref tmp);
+                            d[i] = tmp;
+                            work0[i-ll] = cs;
+                            work1[i-ll] = -sn;
+                            work2[i-ll] = oldcs;
+                            work3[i-ll] = -oldsn;
+                        }
+                        h = d[ll]*cs;
+                        d[ll] = h*oldcs;
+                        e[ll] = h*oldsn;
+                        
+                        //
+                        // Update singular vectors
+                        //
+                        if( ncvt>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, ref work2, ref work3, ref vt, ref vttemp);
+                        }
+                        if( nru>0 )
+                        {
+                            rotations.applyrotationsfromtheright(!fwddir, ustart, uend, ll+ustart-1, m+ustart-1, ref work0, ref work1, ref u, ref utemp);
+                        }
+                        if( ncc>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, ref work0, ref work1, ref c, ref ctemp);
+                        }
+                        
+                        //
+                        // Test convergence
+                        //
+                        if( (double)(Math.Abs(e[ll]))<=(double)(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 = (Math.Abs(d[ll])-shift)*(extsignbdsqr(1, d[ll])+shift/d[ll]);
+                        g = e[ll];
+                        for(i=ll; i<=m-1; i++)
+                        {
+                            rotations.generaterotation(f, g, ref cosr, ref sinr, ref r);
+                            if( i>ll )
+                            {
+                                e[i-1] = r;
+                            }
+                            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];
+                            rotations.generaterotation(f, g, ref cosl, ref sinl, ref r);
+                            d[i] = r;
+                            f = cosl*e[i]+sinl*d[i+1];
+                            d[i+1] = cosl*d[i+1]-sinl*e[i];
+                            if( i<m-1 )
+                            {
+                                g = sinl*e[i+1];
+                                e[i+1] = cosl*e[i+1];
+                            }
+                            work0[i-ll+1] = cosr;
+                            work1[i-ll+1] = sinr;
+                            work2[i-ll+1] = cosl;
+                            work3[i-ll+1] = sinl;
+                        }
+                        e[m-1] = f;
+                        
+                        //
+                        // Update singular vectors
+                        //
+                        if( ncvt>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, ref work0, ref work1, ref vt, ref vttemp);
+                        }
+                        if( nru>0 )
+                        {
+                            rotations.applyrotationsfromtheright(fwddir, ustart, uend, ll+ustart-1, m+ustart-1, ref work2, ref work3, ref u, ref utemp);
+                        }
+                        if( ncc>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, ref work2, ref work3, ref c, ref ctemp);
+                        }
+                        
+                        //
+                        // Test convergence
+                        //
+                        if( (double)(Math.Abs(e[m-1]))<=(double)(thresh) )
+                        {
+                            e[m-1] = 0;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Chase bulge from bottom to top
+                        // Save cosines and sines for later singular vector updates
+                        //
+                        f = (Math.Abs(d[m])-shift)*(extsignbdsqr(1, d[m])+shift/d[m]);
+                        g = e[m-1];
+                        for(i=m; i>=ll+1; i--)
+                        {
+                            rotations.generaterotation(f, g, ref cosr, ref sinr, ref r);
+                            if( i<m )
+                            {
+                                e[i] = r;
+                            }
+                            f = cosr*d[i]+sinr*e[i-1];
+                            e[i-1] = cosr*e[i-1]-sinr*d[i];
+                            g = sinr*d[i-1];
+                            d[i-1] = cosr*d[i-1];
+                            rotations.generaterotation(f, g, ref cosl, ref sinl, ref r);
+                            d[i] = r;
+                            f = cosl*e[i-1]+sinl*d[i-1];
+                            d[i-1] = cosl*d[i-1]-sinl*e[i-1];
+                            if( i>ll+1 )
+                            {
+                                g = sinl*e[i-2];
+                                e[i-2] = cosl*e[i-2];
+                            }
+                            work0[i-ll] = cosr;
+                            work1[i-ll] = -sinr;
+                            work2[i-ll] = cosl;
+                            work3[i-ll] = -sinl;
+                        }
+                        e[ll] = f;
+                        
+                        //
+                        // Test convergence
+                        //
+                        if( (double)(Math.Abs(e[ll]))<=(double)(thresh) )
+                        {
+                            e[ll] = 0;
+                        }
+                        
+                        //
+                        // Update singular vectors if desired
+                        //
+                        if( ncvt>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, ref work2, ref work3, ref vt, ref vttemp);
+                        }
+                        if( nru>0 )
+                        {
+                            rotations.applyrotationsfromtheright(!fwddir, ustart, uend, ll+ustart-1, m+ustart-1, ref work0, ref work1, ref u, ref utemp);
+                        }
+                        if( ncc>0 )
+                        {
+                            rotations.applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, ref work0, ref work1, ref c, ref ctemp);
+                        }
+                    }
+                }
+                
+                //
+                // QR iteration finished, go back and check convergence
+                //
+                continue;
+            }
+            
+            //
+            // All singular values converged, so make them positive
+            //
+            for(i=1; i<=n; i++)
+            {
+                if( (double)(d[i])<(double)(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,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; i<=n-1; i++)
+            {
+                
+                //
+                // Scan for smallest D(I)
+                //
+                isub = 1;
+                smin = d[1];
+                for(j=2; j<=n+1-i; j++)
+                {
+                    if( (double)(d[j])<=(double)(smin) )
+                    {
+                        isub = j;
+                        smin = d[j];
+                    }
+                }
+                if( isub!=n+1-i )
+                {
+                    
+                    //
+                    // Swap singular values and vectors
+                    //
+                    d[isub] = d[n+1-i];
+                    d[n+1-i] = smin;
+                    if( ncvt>0 )
+                    {
+                        j = n+1-i;
+                        for(i_=vstart; i_<=vend;i_++)
+                        {
+                            vttemp[i_] = vt[isub+vstart-1,i_];
+                        }
+                        for(i_=vstart; i_<=vend;i_++)
+                        {
+                            vt[isub+vstart-1,i_] = vt[j+vstart-1,i_];
+                        }
+                        for(i_=vstart; i_<=vend;i_++)
+                        {
+                            vt[j+vstart-1,i_] = vttemp[i_];
+                        }
+                    }
+                    if( nru>0 )
+                    {
+                        j = n+1-i;
+                        for(i_=ustart; i_<=uend;i_++)
+                        {
+                            utemp[i_] = u[i_,isub+ustart-1];
+                        }
+                        for(i_=ustart; i_<=uend;i_++)
+                        {
+                            u[i_,isub+ustart-1] = u[i_,j+ustart-1];
+                        }
+                        for(i_=ustart; i_<=uend;i_++)
+                        {
+                            u[i_,j+ustart-1] = utemp[i_];
+                        }
+                    }
+                    if( ncc>0 )
+                    {
+                        j = n+1-i;
+                        for(i_=cstart; i_<=cend;i_++)
+                        {
+                            ctemp[i_] = c[isub+cstart-1,i_];
+                        }
+                        for(i_=cstart; i_<=cend;i_++)
+                        {
+                            c[isub+cstart-1,i_] = c[j+cstart-1,i_];
+                        }
+                        for(i_=cstart; i_<=cend;i_++)
+                        {
+                            c[j+cstart-1,i_] = ctemp[i_];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        private static double extsignbdsqr(double a,
+            double b)
+        {
+            double result = 0;
+
+            if( (double)(b)>=(double)(0) )
+            {
+                result = Math.Abs(a);
+            }
+            else
+            {
+                result = -Math.Abs(a);
+            }
+            return result;
+        }
+
+
+        private static void svd2x2(double f,
+            double g,
+            double h,
+            ref double ssmin,
+            ref double ssmax)
+        {
+            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;
+
+            fa = Math.Abs(f);
+            ga = Math.Abs(g);
+            ha = Math.Abs(h);
+            fhmn = Math.Min(fa, ha);
+            fhmx = Math.Max(fa, ha);
+            if( (double)(fhmn)==(double)(0) )
+            {
+                ssmin = 0;
+                if( (double)(fhmx)==(double)(0) )
+                {
+                    ssmax = ga;
+                }
+                else
+                {
+                    ssmax = Math.Max(fhmx, ga)*Math.Sqrt(1+AP.Math.Sqr(Math.Min(fhmx, ga)/Math.Max(fhmx, ga)));
+                }
+            }
+            else
+            {
+                if( (double)(ga)<(double)(fhmx) )
+                {
+                    aas = 1+fhmn/fhmx;
+                    at = (fhmx-fhmn)/fhmx;
+                    au = AP.Math.Sqr(ga/fhmx);
+                    c = 2/(Math.Sqrt(aas*aas+au)+Math.Sqrt(at*at+au));
+                    ssmin = fhmn*c;
+                    ssmax = fhmx/c;
+                }
+                else
+                {
+                    au = fhmx/ga;
+                    if( (double)(au)==(double)(0) )
+                    {
+                        
+                        //
+                        // Avoid possible harmful underflow if exponent range
+                        // asymmetric (true SSMIN may not underflow even if
+                        // AU underflows)
+                        //
+                        ssmin = fhmn*fhmx/ga;
+                        ssmax = ga;
+                    }
+                    else
+                    {
+                        aas = 1+fhmn/fhmx;
+                        at = (fhmx-fhmn)/fhmx;
+                        c = 1/(Math.Sqrt(1+AP.Math.Sqr(aas*au))+Math.Sqrt(1+AP.Math.Sqr(at*au)));
+                        ssmin = fhmn*c*au;
+                        ssmin = ssmin+ssmin;
+                        ssmax = ga/(c+c);
+                    }
+                }
+            }
+        }
+
+
+        private static void svdv2x2(double f,
+            double g,
+            double h,
+            ref double ssmin,
+            ref double ssmax,
+            ref double snr,
+            ref double csr,
+            ref double snl,
+            ref double csl)
+        {
+            bool gasmal = new bool();
+            bool swp = new bool();
+            int pmax = 0;
+            double a = 0;
+            double clt = 0;
+            double crt = 0;
+            double d = 0;
+            double fa = 0;
+            double ft = 0;
+            double ga = 0;
+            double gt = 0;
+            double ha = 0;
+            double ht = 0;
+            double l = 0;
+            double m = 0;
+            double mm = 0;
+            double r = 0;
+            double s = 0;
+            double slt = 0;
+            double srt = 0;
+            double t = 0;
+            double temp = 0;
+            double tsign = 0;
+            double tt = 0;
+            double v = 0;
+
+            ft = f;
+            fa = Math.Abs(ft);
+            ht = h;
+            ha = Math.Abs(h);
+            
+            //
+            // PMAX points to the maximum absolute element of matrix
+            //  PMAX = 1 if F largest in absolute values
+            //  PMAX = 2 if G largest in absolute values
+            //  PMAX = 3 if H largest in absolute values
+            //
+            pmax = 1;
+            swp = (double)(ha)>(double)(fa);
+            if( swp )
+            {
+                
+                //
+                // Now FA .ge. HA
+                //
+                pmax = 3;
+                temp = ft;
+                ft = ht;
+                ht = temp;
+                temp = fa;
+                fa = ha;
+                ha = temp;
+            }
+            gt = g;
+            ga = Math.Abs(gt);
+            if( (double)(ga)==(double)(0) )
+            {
+                
+                //
+                // Diagonal matrix
+                //
+                ssmin = ha;
+                ssmax = fa;
+                clt = 1;
+                crt = 1;
+                slt = 0;
+                srt = 0;
+            }
+            else
+            {
+                gasmal = true;
+                if( (double)(ga)>(double)(fa) )
+                {
+                    pmax = 2;
+                    if( (double)(fa/ga)<(double)(AP.Math.MachineEpsilon) )
+                    {
+                        
+                        //
+                        // Case of very large GA
+                        //
+                        gasmal = false;
+                        ssmax = ga;
+                        if( (double)(ha)>(double)(1) )
+                        {
+                            v = ga/ha;
+                            ssmin = fa/v;
+                        }
+                        else
+                        {
+                            v = fa/ga;
+                            ssmin = v*ha;
+                        }
+                        clt = 1;
+                        slt = ht/gt;
+                        srt = 1;
+                        crt = ft/gt;
+                    }
+                }
+                if( gasmal )
+                {
+                    
+                    //
+                    // Normal case
+                    //
+                    d = fa-ha;
+                    if( (double)(d)==(double)(fa) )
+                    {
+                        l = 1;
+                    }
+                    else
+                    {
+                        l = d/fa;
+                    }
+                    m = gt/ft;
+                    t = 2-l;
+                    mm = m*m;
+                    tt = t*t;
+                    s = Math.Sqrt(tt+mm);
+                    if( (double)(l)==(double)(0) )
+                    {
+                        r = Math.Abs(m);
+                    }
+                    else
+                    {
+                        r = Math.Sqrt(l*l+mm);
+                    }
+                    a = 0.5*(s+r);
+                    ssmin = ha/a;
+                    ssmax = fa*a;
+                    if( (double)(mm)==(double)(0) )
+                    {
+                        
+                        //
+                        // Note that M is very tiny
+                        //
+                        if( (double)(l)==(double)(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);
+                    }
+                    l = Math.Sqrt(t*t+4);
+                    crt = 2/l;
+                    srt = t/l;
+                    clt = (crt+srt*m)/a;
+                    v = ht/ft;
+                    slt = v*srt/a;
+                }
+            }
+            if( swp )
+            {
+                csl = srt;
+                snl = crt;
+                csr = slt;
+                snr = clt;
+            }
+            else
+            {
+                csl = clt;
+                snl = slt;
+                csr = crt;
+                snr = srt;
+            }
+            
+            //
+            // Correct signs of SSMAX and SSMIN
+            //
+            if( pmax==1 )
+            {
+                tsign = extsignbdsqr(1, csr)*extsignbdsqr(1, csl)*extsignbdsqr(1, f);
+            }
+            if( pmax==2 )
+            {
+                tsign = extsignbdsqr(1, snr)*extsignbdsqr(1, csl)*extsignbdsqr(1, g);
+            }
+            if( pmax==3 )
+            {
+                tsign = extsignbdsqr(1, snr)*extsignbdsqr(1, snl)*extsignbdsqr(1, h);
+            }
+            ssmax = extsignbdsqr(ssmax, tsign);
+            ssmin = extsignbdsqr(ssmin, tsign*extsignbdsqr(1, f)*extsignbdsqr(1, h));
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bessel.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bessel.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bessel.cs	(revision 2645)
@@ -0,0 +1,1210 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class bessel
+    {
+        /*************************************************************************
+        Bessel function of order zero
+
+        Returns Bessel function of order zero of the argument.
+
+        The domain is divided into the intervals [0, 5] and
+        (5, infinity). In the first interval the following rational
+        approximation is used:
+
+
+               2         2
+        (w - r  ) (w - r  ) P (w) / Q (w)
+              1         2    3       8
+
+                   2
+        where w = x  and the two r's are zeros of the function.
+
+        In the second interval, the Hankel asymptotic expansion
+        is employed with two rational functions of degree 6/6
+        and 7/7.
+
+        ACCURACY:
+
+                             Absolute error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       60000       4.2e-16     1.1e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besselj0(double x)
+        {
+            double result = 0;
+            double xsq = 0;
+            double nn = 0;
+            double pzero = 0;
+            double qzero = 0;
+            double p1 = 0;
+            double q1 = 0;
+
+            if( (double)(x)<(double)(0) )
+            {
+                x = -x;
+            }
+            if( (double)(x)>(double)(8.0) )
+            {
+                besselasympt0(x, ref pzero, ref qzero);
+                nn = x-Math.PI/4;
+                result = Math.Sqrt(2/Math.PI/x)*(pzero*Math.Cos(nn)-qzero*Math.Sin(nn));
+                return result;
+            }
+            xsq = AP.Math.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;
+            result = p1/q1;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Bessel function of order one
+
+        Returns Bessel function of order one of the argument.
+
+        The domain is divided into the intervals [0, 8] and
+        (8, infinity). In the first interval a 24 term Chebyshev
+        expansion is used. In the second, the asymptotic
+        trigonometric representation is employed using two
+        rational functions of degree 5/5.
+
+        ACCURACY:
+
+                             Absolute error:
+        arithmetic   domain      # trials      peak         rms
+           IEEE      0, 30       30000       2.6e-16     1.1e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besselj1(double x)
+        {
+            double result = 0;
+            double s = 0;
+            double xsq = 0;
+            double nn = 0;
+            double pzero = 0;
+            double qzero = 0;
+            double p1 = 0;
+            double q1 = 0;
+
+            s = Math.Sign(x);
+            if( (double)(x)<(double)(0) )
+            {
+                x = -x;
+            }
+            if( (double)(x)>(double)(8.0) )
+            {
+                besselasympt1(x, ref pzero, ref qzero);
+                nn = x-3*Math.PI/4;
+                result = Math.Sqrt(2/Math.PI/x)*(pzero*Math.Cos(nn)-qzero*Math.Sin(nn));
+                if( (double)(s)<(double)(0) )
+                {
+                    result = -result;
+                }
+                return result;
+            }
+            xsq = AP.Math.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;
+            result = s*x*p1/q1;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Bessel function of integer order
+
+        Returns Bessel function of order n, where n is a
+        (possibly negative) integer.
+
+        The ratio of jn(x) to j0(x) is computed by backward
+        recurrence.  First the ratio jn/jn-1 is found by a
+        continued fraction expansion.  Then the recurrence
+        relating successive orders is applied until j0 or j1 is
+        reached.
+
+        If n = 0 or 1 the routine for j0 or j1 is called
+        directly.
+
+        ACCURACY:
+
+                             Absolute error:
+        arithmetic   range      # trials      peak         rms
+           IEEE      0, 30        5000       4.4e-16     7.9e-17
+
+
+        Not suitable for large n or x. Use jv() (fractional order) instead.
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besseljn(int n,
+            double x)
+        {
+            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;
+
+            if( n<0 )
+            {
+                n = -n;
+                if( n%2==0 )
+                {
+                    sg = 1;
+                }
+                else
+                {
+                    sg = -1;
+                }
+            }
+            else
+            {
+                sg = 1;
+            }
+            if( (double)(x)<(double)(0) )
+            {
+                if( n%2!=0 )
+                {
+                    sg = -sg;
+                }
+                x = -x;
+            }
+            if( n==0 )
+            {
+                result = sg*besselj0(x);
+                return result;
+            }
+            if( n==1 )
+            {
+                result = sg*besselj1(x);
+                return result;
+            }
+            if( n==2 )
+            {
+                if( (double)(x)==(double)(0) )
+                {
+                    result = 0;
+                }
+                else
+                {
+                    result = sg*(2.0*besselj1(x)/x-besselj0(x));
+                }
+                return result;
+            }
+            if( (double)(x)<(double)(AP.Math.MachineEpsilon) )
+            {
+                result = 0;
+                return result;
+            }
+            k = 53;
+            pk = 2*(n+k);
+            ans = pk;
+            xk = x*x;
+            do
+            {
+                pk = pk-2.0;
+                ans = pk-xk/ans;
+                k = k-1;
+            }
+            while( k!=0 );
+            ans = x/ans;
+            pk = 1.0;
+            pkm1 = 1.0/ans;
+            k = n-1;
+            r = 2*k;
+            do
+            {
+                pkm2 = (pkm1*r-pk*x)/x;
+                pk = pkm1;
+                pkm1 = pkm2;
+                r = r-2.0;
+                k = k-1;
+            }
+            while( k!=0 );
+            if( (double)(Math.Abs(pk))>(double)(Math.Abs(pkm1)) )
+            {
+                ans = besselj1(x)/pk;
+            }
+            else
+            {
+                ans = besselj0(x)/pkm1;
+            }
+            result = sg*ans;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Bessel function of the second kind, order zero
+
+        Returns Bessel function of the second kind, of order
+        zero, of the argument.
+
+        The domain is divided into the intervals [0, 5] and
+        (5, infinity). In the first interval a rational approximation
+        R(x) is employed to compute
+          y0(x)  = R(x)  +   2 * log(x) * j0(x) / PI.
+        Thus a call to j0() is required.
+
+        In the second interval, the Hankel asymptotic expansion
+        is employed with two rational functions of degree 6/6
+        and 7/7.
+
+
+
+        ACCURACY:
+
+         Absolute error, when y0(x) < 1; else relative error:
+
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       30000       1.3e-15     1.6e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double bessely0(double x)
+        {
+            double result = 0;
+            double nn = 0;
+            double xsq = 0;
+            double pzero = 0;
+            double qzero = 0;
+            double p4 = 0;
+            double q4 = 0;
+
+            if( (double)(x)>(double)(8.0) )
+            {
+                besselasympt0(x, ref pzero, ref qzero);
+                nn = x-Math.PI/4;
+                result = Math.Sqrt(2/Math.PI/x)*(pzero*Math.Sin(nn)+qzero*Math.Cos(nn));
+                return result;
+            }
+            xsq = AP.Math.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;
+            result = p4/q4+2/Math.PI*besselj0(x)*Math.Log(x);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Bessel function of second kind of order one
+
+        Returns Bessel function of the second kind of order one
+        of the argument.
+
+        The domain is divided into the intervals [0, 8] and
+        (8, infinity). In the first interval a 25 term Chebyshev
+        expansion is used, and a call to j1() is required.
+        In the second, the asymptotic trigonometric representation
+        is employed using two rational functions of degree 5/5.
+
+        ACCURACY:
+
+                             Absolute error:
+        arithmetic   domain      # trials      peak         rms
+           IEEE      0, 30       30000       1.0e-15     1.3e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double bessely1(double x)
+        {
+            double result = 0;
+            double nn = 0;
+            double xsq = 0;
+            double pzero = 0;
+            double qzero = 0;
+            double p4 = 0;
+            double q4 = 0;
+
+            if( (double)(x)>(double)(8.0) )
+            {
+                besselasympt1(x, ref pzero, ref qzero);
+                nn = x-3*Math.PI/4;
+                result = Math.Sqrt(2/Math.PI/x)*(pzero*Math.Sin(nn)+qzero*Math.Cos(nn));
+                return result;
+            }
+            xsq = AP.Math.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;
+            result = x*p4/q4+2/Math.PI*(besselj1(x)*Math.Log(x)-1/x);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Bessel function of second kind of integer order
+
+        Returns Bessel function of order n, where n is a
+        (possibly negative) integer.
+
+        The function is evaluated by forward recurrence on
+        n, starting with values computed by the routines
+        y0() and y1().
+
+        If n = 0 or 1 the routine for y0 or y1 is called
+        directly.
+
+        ACCURACY:
+                             Absolute error, except relative
+                             when y > 1:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       30000       3.4e-15     4.3e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besselyn(int n,
+            double x)
+        {
+            double result = 0;
+            int i = 0;
+            double a = 0;
+            double b = 0;
+            double tmp = 0;
+            double s = 0;
+
+            s = 1;
+            if( n<0 )
+            {
+                n = -n;
+                if( n%2!=0 )
+                {
+                    s = -1;
+                }
+            }
+            if( n==0 )
+            {
+                result = bessely0(x);
+                return result;
+            }
+            if( n==1 )
+            {
+                result = s*bessely1(x);
+                return result;
+            }
+            a = bessely0(x);
+            b = bessely1(x);
+            for(i=1; i<=n-1; i++)
+            {
+                tmp = b;
+                b = 2*i/x*b-a;
+                a = tmp;
+            }
+            result = s*b;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Modified Bessel function of order zero
+
+        Returns modified Bessel function of order zero of the
+        argument.
+
+        The function is defined as i0(x) = j0( ix ).
+
+        The range is partitioned into the two intervals [0,8] and
+        (8, infinity).  Chebyshev polynomial expansions are employed
+        in each interval.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,30        30000       5.8e-16     1.4e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besseli0(double x)
+        {
+            double result = 0;
+            double y = 0;
+            double v = 0;
+            double z = 0;
+            double b0 = 0;
+            double b1 = 0;
+            double b2 = 0;
+
+            if( (double)(x)<(double)(0) )
+            {
+                x = -x;
+            }
+            if( (double)(x)<=(double)(8.0) )
+            {
+                y = x/2.0-2.0;
+                besselmfirstcheb(-4.41534164647933937950E-18, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 3.33079451882223809783E-17, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -2.43127984654795469359E-16, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.71539128555513303061E-15, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -1.16853328779934516808E-14, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 7.67618549860493561688E-14, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -4.85644678311192946090E-13, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 2.95505266312963983461E-12, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -1.72682629144155570723E-11, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 9.67580903537323691224E-11, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -5.18979560163526290666E-10, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 2.65982372468238665035E-9, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -1.30002500998624804212E-8, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 6.04699502254191894932E-8, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -2.67079385394061173391E-7, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.11738753912010371815E-6, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -4.41673835845875056359E-6, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.64484480707288970893E-5, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -5.75419501008210370398E-5, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.88502885095841655729E-4, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -5.76375574538582365885E-4, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.63947561694133579842E-3, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -4.32430999505057594430E-3, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.05464603945949983183E-2, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -2.37374148058994688156E-2, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 4.93052842396707084878E-2, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -9.49010970480476444210E-2, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.71620901522208775349E-1, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -3.04682672343198398683E-1, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 6.76795274409476084995E-1, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                result = Math.Exp(x)*v;
+                return result;
+            }
+            z = 32.0/x-2.0;
+            besselmfirstcheb(-7.23318048787475395456E-18, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -4.83050448594418207126E-18, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 4.46562142029675999901E-17, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 3.46122286769746109310E-17, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -2.82762398051658348494E-16, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -3.42548561967721913462E-16, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 1.77256013305652638360E-15, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 3.81168066935262242075E-15, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -9.55484669882830764870E-15, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -4.15056934728722208663E-14, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 1.54008621752140982691E-14, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 3.85277838274214270114E-13, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 7.18012445138366623367E-13, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -1.79417853150680611778E-12, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -1.32158118404477131188E-11, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, -3.14991652796324136454E-11, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 1.18891471078464383424E-11, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 4.94060238822496958910E-10, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 3.39623202570838634515E-9, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 2.26666899049817806459E-8, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 2.04891858946906374183E-7, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 2.89137052083475648297E-6, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 6.88975834691682398426E-5, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 3.36911647825569408990E-3, ref b0, ref b1, ref b2);
+            besselmnextcheb(z, 8.04490411014108831608E-1, ref b0, ref b1, ref b2);
+            v = 0.5*(b0-b2);
+            result = Math.Exp(x)*v/Math.Sqrt(x);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Modified Bessel function of order one
+
+        Returns modified Bessel function of order one of the
+        argument.
+
+        The function is defined as i1(x) = -i j1( ix ).
+
+        The range is partitioned into the two intervals [0,8] and
+        (8, infinity).  Chebyshev polynomial expansions are employed
+        in each interval.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       30000       1.9e-15     2.1e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1985, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besseli1(double x)
+        {
+            double result = 0;
+            double y = 0;
+            double z = 0;
+            double v = 0;
+            double b0 = 0;
+            double b1 = 0;
+            double b2 = 0;
+
+            z = Math.Abs(x);
+            if( (double)(z)<=(double)(8.0) )
+            {
+                y = z/2.0-2.0;
+                besselm1firstcheb(2.77791411276104639959E-18, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.11142121435816608115E-17, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.55363195773620046921E-16, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.10559694773538630805E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 7.60068429473540693410E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -5.04218550472791168711E-14, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 3.22379336594557470981E-13, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.98397439776494371520E-12, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.17361862988909016308E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -6.66348972350202774223E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 3.62559028155211703701E-10, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.88724975172282928790E-9, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 9.38153738649577178388E-9, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -4.44505912879632808065E-8, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.00329475355213526229E-7, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -8.56872026469545474066E-7, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 3.47025130813767847674E-6, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.32731636560394358279E-5, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 4.78156510755005422638E-5, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.61760815825896745588E-4, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 5.12285956168575772895E-4, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.51357245063125314899E-3, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 4.15642294431288815669E-3, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.05640848946261981558E-2, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.47264490306265168283E-2, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -5.29459812080949914269E-2, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.02643658689847095384E-1, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.76416518357834055153E-1, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.52587186443633654823E-1, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                z = v*z*Math.Exp(z);
+            }
+            else
+            {
+                y = 32.0/z-2.0;
+                besselm1firstcheb(7.51729631084210481353E-18, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 4.41434832307170791151E-18, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -4.65030536848935832153E-17, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -3.20952592199342395980E-17, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.96262899764595013876E-16, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 3.30820231092092828324E-16, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.88035477551078244854E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -3.81440307243700780478E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.04202769841288027642E-14, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 4.27244001671195135429E-14, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.10154184277266431302E-14, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -4.08355111109219731823E-13, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -7.19855177624590851209E-13, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.03562854414708950722E-12, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.41258074366137813316E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 3.25260358301548823856E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.89749581235054123450E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -5.58974346219658380687E-10, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -3.83538038596423702205E-9, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.63146884688951950684E-8, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.51223623787020892529E-7, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -3.88256480887769039346E-6, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.10588938762623716291E-4, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -9.76109749136146840777E-3, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 7.78576235018280120474E-1, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                z = v*Math.Exp(z)/Math.Sqrt(z);
+            }
+            if( (double)(x)<(double)(0) )
+            {
+                z = -z;
+            }
+            result = z;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Modified Bessel function, second kind, order zero
+
+        Returns modified Bessel function of the second kind
+        of order zero of the argument.
+
+        The range is partitioned into the two intervals [0,8] and
+        (8, infinity).  Chebyshev polynomial expansions are employed
+        in each interval.
+
+        ACCURACY:
+
+        Tested at 2000 random points between 0 and 8.  Peak absolute
+        error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15.
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       30000       1.2e-15     1.6e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besselk0(double x)
+        {
+            double result = 0;
+            double y = 0;
+            double z = 0;
+            double v = 0;
+            double b0 = 0;
+            double b1 = 0;
+            double b2 = 0;
+
+            System.Diagnostics.Debug.Assert((double)(x)>(double)(0), "Domain error in BesselK0: x<=0");
+            if( (double)(x)<=(double)(2) )
+            {
+                y = x*x-2.0;
+                besselmfirstcheb(1.37446543561352307156E-16, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 4.25981614279661018399E-14, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.03496952576338420167E-11, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.90451637722020886025E-9, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 2.53479107902614945675E-7, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 2.28621210311945178607E-5, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 1.26461541144692592338E-3, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 3.59799365153615016266E-2, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, 3.44289899924628486886E-1, ref b0, ref b1, ref b2);
+                besselmnextcheb(y, -5.35327393233902768720E-1, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                v = v-Math.Log(0.5*x)*besseli0(x);
+            }
+            else
+            {
+                z = 8.0/x-2.0;
+                besselmfirstcheb(5.30043377268626276149E-18, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -1.64758043015242134646E-17, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 5.21039150503902756861E-17, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -1.67823109680541210385E-16, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 5.51205597852431940784E-16, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -1.84859337734377901440E-15, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 6.34007647740507060557E-15, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -2.22751332699166985548E-14, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 8.03289077536357521100E-14, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -2.98009692317273043925E-13, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 1.14034058820847496303E-12, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -4.51459788337394416547E-12, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 1.85594911495471785253E-11, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -7.95748924447710747776E-11, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 3.57739728140030116597E-10, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -1.69753450938905987466E-9, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 8.57403401741422608519E-9, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -4.66048989768794782956E-8, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 2.76681363944501510342E-7, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -1.83175552271911948767E-6, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 1.39498137188764993662E-5, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -1.28495495816278026384E-4, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 1.56988388573005337491E-3, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, -3.14481013119645005427E-2, ref b0, ref b1, ref b2);
+                besselmnextcheb(z, 2.44030308206595545468E0, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                v = v*Math.Exp(-x)/Math.Sqrt(x);
+            }
+            result = v;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Modified Bessel function, second kind, order one
+
+        Computes the modified Bessel function of the second kind
+        of order one of the argument.
+
+        The range is partitioned into the two intervals [0,2] and
+        (2, infinity).  Chebyshev polynomial expansions are employed
+        in each interval.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       30000       1.2e-15     1.6e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besselk1(double x)
+        {
+            double result = 0;
+            double y = 0;
+            double z = 0;
+            double v = 0;
+            double b0 = 0;
+            double b1 = 0;
+            double b2 = 0;
+
+            z = 0.5*x;
+            System.Diagnostics.Debug.Assert((double)(z)>(double)(0), "Domain error in K1");
+            if( (double)(x)<=(double)(2) )
+            {
+                y = x*x-2.0;
+                besselm1firstcheb(-7.02386347938628759343E-18, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.42744985051936593393E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -6.66690169419932900609E-13, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.41148839263352776110E-10, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.21338763073472585583E-8, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.43340614156596823496E-6, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.73028895751305206302E-4, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -6.97572385963986435018E-3, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.22611180822657148235E-1, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -3.53155960776544875667E-1, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.52530022733894777053E0, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                result = Math.Log(z)*besseli1(x)+v/x;
+            }
+            else
+            {
+                y = 8.0/x-2.0;
+                besselm1firstcheb(-5.75674448366501715755E-18, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.79405087314755922667E-17, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -5.68946255844285935196E-17, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.83809354436663880070E-16, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -6.05704724837331885336E-16, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.03870316562433424052E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -7.01983709041831346144E-15, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.47715442448130437068E-14, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -8.97670518232499435011E-14, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 3.34841966607842919884E-13, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.28917396095102890680E-12, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 5.13963967348173025100E-12, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.12996783842756842877E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 9.21831518760500529508E-11, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -4.19035475934189648750E-10, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.01504975519703286596E-9, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.03457624656780970260E-8, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 5.74108412545004946722E-8, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -3.50196060308781257119E-7, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.40648494783721712015E-6, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -1.93619797416608296024E-5, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.95215518471351631108E-4, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, -2.85781685962277938680E-3, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 1.03923736576817238437E-1, ref b0, ref b1, ref b2);
+                besselm1nextcheb(y, 2.72062619048444266945E0, ref b0, ref b1, ref b2);
+                v = 0.5*(b0-b2);
+                result = Math.Exp(-x)*v/Math.Sqrt(x);
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Modified Bessel function, second kind, integer order
+
+        Returns modified Bessel function of the second kind
+        of order n of the argument.
+
+        The range is partitioned into the two intervals [0,9.55] and
+        (9.55, infinity).  An ascending power series is used in the
+        low range, and an asymptotic expansion in the high range.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,30        90000       1.8e-8      3.0e-10
+
+        Error is high only near the crossover point x = 9.55
+        between the two expansions used.
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double besselkn(int nn,
+            double x)
+        {
+            double result = 0;
+            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;
+
+            eul = 5.772156649015328606065e-1;
+            if( nn<0 )
+            {
+                n = -nn;
+            }
+            else
+            {
+                n = nn;
+            }
+            System.Diagnostics.Debug.Assert(n<=31, "Overflow in BesselKN");
+            System.Diagnostics.Debug.Assert((double)(x)>(double)(0), "Domain error in BesselKN");
+            if( (double)(x)<=(double)(9.55) )
+            {
+                ans = 0.0;
+                z0 = 0.25*x*x;
+                fn = 1.0;
+                pn = 0.0;
+                zmn = 1.0;
+                tox = 2.0/x;
+                if( n>0 )
+                {
+                    pn = -eul;
+                    k = 1.0;
+                    for(i=1; i<=n-1; i++)
+                    {
+                        pn = pn+1.0/k;
+                        k = k+1.0;
+                        fn = fn*k;
+                    }
+                    zmn = tox;
+                    if( n==1 )
+                    {
+                        ans = 1.0/x;
+                    }
+                    else
+                    {
+                        nk1f = fn/n;
+                        kf = 1.0;
+                        s = nk1f;
+                        z = -z0;
+                        zn = 1.0;
+                        for(i=1; i<=n-1; i++)
+                        {
+                            nk1f = nk1f/(n-i);
+                            kf = kf*i;
+                            zn = zn*z;
+                            t = nk1f*zn/kf;
+                            s = s+t;
+                            System.Diagnostics.Debug.Assert((double)(AP.Math.MaxRealNumber-Math.Abs(t))>(double)(Math.Abs(s)), "Overflow in BesselKN");
+                            System.Diagnostics.Debug.Assert(!((double)(tox)>(double)(1.0) & (double)(AP.Math.MaxRealNumber/tox)<(double)(zmn)), "Overflow in BesselKN");
+                            zmn = zmn*tox;
+                        }
+                        s = s*0.5;
+                        t = Math.Abs(s);
+                        System.Diagnostics.Debug.Assert(!((double)(zmn)>(double)(1.0) & (double)(AP.Math.MaxRealNumber/zmn)<(double)(t)), "Overflow in BesselKN");
+                        System.Diagnostics.Debug.Assert(!((double)(t)>(double)(1.0) & (double)(AP.Math.MaxRealNumber/t)<(double)(zmn)), "Overflow in BesselKN");
+                        ans = s*zmn;
+                    }
+                }
+                tlg = 2.0*Math.Log(0.5*x);
+                pk = -eul;
+                if( n==0 )
+                {
+                    pn = pk;
+                    t = 1.0;
+                }
+                else
+                {
+                    pn = pn+1.0/n;
+                    t = 1.0/fn;
+                }
+                s = (pk+pn-tlg)*t;
+                k = 1.0;
+                do
+                {
+                    t = t*(z0/(k*(k+n)));
+                    pk = pk+1.0/k;
+                    pn = pn+1.0/(k+n);
+                    s = s+(pk+pn-tlg)*t;
+                    k = k+1.0;
+                }
+                while( (double)(Math.Abs(t/s))>(double)(AP.Math.MachineEpsilon) );
+                s = 0.5*s/zmn;
+                if( n%2!=0 )
+                {
+                    s = -s;
+                }
+                ans = ans+s;
+                result = ans;
+                return result;
+            }
+            if( (double)(x)>(double)(Math.Log(AP.Math.MaxRealNumber)) )
+            {
+                result = 0;
+                return result;
+            }
+            k = n;
+            pn = 4.0*k*k;
+            pk = 1.0;
+            z0 = 8.0*x;
+            fn = 1.0;
+            t = 1.0;
+            s = t;
+            nkf = AP.Math.MaxRealNumber;
+            i = 0;
+            do
+            {
+                z = pn-pk*pk;
+                t = t*z/(fn*z0);
+                nk1f = Math.Abs(t);
+                if( i>=n & (double)(nk1f)>(double)(nkf) )
+                {
+                    break;
+                }
+                nkf = nk1f;
+                s = s+t;
+                fn = fn+1.0;
+                pk = pk+2.0;
+                i = i+1;
+            }
+            while( (double)(Math.Abs(t/s))>(double)(AP.Math.MachineEpsilon) );
+            result = Math.Exp(-x)*Math.Sqrt(Math.PI/(2.0*x))*s;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static void besselmfirstcheb(double c,
+            ref double b0,
+            ref double b1,
+            ref double b2)
+        {
+            b0 = c;
+            b1 = 0.0;
+            b2 = 0.0;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static void besselmnextcheb(double x,
+            double c,
+            ref double b0,
+            ref double b1,
+            ref double b2)
+        {
+            b2 = b1;
+            b1 = b0;
+            b0 = x*b1-b2+c;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static void besselm1firstcheb(double c,
+            ref double b0,
+            ref double b1,
+            ref double b2)
+        {
+            b0 = c;
+            b1 = 0.0;
+            b2 = 0.0;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static void besselm1nextcheb(double x,
+            double c,
+            ref double b0,
+            ref double b1,
+            ref double b2)
+        {
+            b2 = b1;
+            b1 = b0;
+            b0 = x*b1-b2+c;
+        }
+
+
+        private static void besselasympt0(double x,
+            ref double pzero,
+            ref double qzero)
+        {
+            double xsq = 0;
+            double p2 = 0;
+            double q2 = 0;
+            double p3 = 0;
+            double q3 = 0;
+
+            xsq = 64.0/(x*x);
+            p2 = 0.0;
+            p2 = 2485.271928957404011288128951+xsq*p2;
+            p2 = 153982.6532623911470917825993+xsq*p2;
+            p2 = 2016135.283049983642487182349+xsq*p2;
+            p2 = 8413041.456550439208464315611+xsq*p2;
+            p2 = 12332384.76817638145232406055+xsq*p2;
+            p2 = 5393485.083869438325262122897+xsq*p2;
+            q2 = 1.0;
+            q2 = 2615.700736920839685159081813+xsq*q2;
+            q2 = 156001.7276940030940592769933+xsq*q2;
+            q2 = 2025066.801570134013891035236+xsq*q2;
+            q2 = 8426449.050629797331554404810+xsq*q2;
+            q2 = 12338310.22786324960844856182+xsq*q2;
+            q2 = 5393485.083869438325560444960+xsq*q2;
+            p3 = -0.0;
+            p3 = -4.887199395841261531199129300+xsq*p3;
+            p3 = -226.2630641933704113967255053+xsq*p3;
+            p3 = -2365.956170779108192723612816+xsq*p3;
+            p3 = -8239.066313485606568803548860+xsq*p3;
+            p3 = -10381.41698748464093880530341+xsq*p3;
+            p3 = -3984.617357595222463506790588+xsq*p3;
+            q3 = 1.0;
+            q3 = 408.7714673983499223402830260+xsq*q3;
+            q3 = 15704.89191515395519392882766+xsq*q3;
+            q3 = 156021.3206679291652539287109+xsq*q3;
+            q3 = 533291.3634216897168722255057+xsq*q3;
+            q3 = 666745.4239319826986004038103+xsq*q3;
+            q3 = 255015.5108860942382983170882+xsq*q3;
+            pzero = p2/q2;
+            qzero = 8*p3/q3/x;
+        }
+
+
+        private static void besselasympt1(double x,
+            ref double pzero,
+            ref double qzero)
+        {
+            double xsq = 0;
+            double p2 = 0;
+            double q2 = 0;
+            double p3 = 0;
+            double q3 = 0;
+
+            xsq = 64.0/(x*x);
+            p2 = -1611.616644324610116477412898;
+            p2 = -109824.0554345934672737413139+xsq*p2;
+            p2 = -1523529.351181137383255105722+xsq*p2;
+            p2 = -6603373.248364939109255245434+xsq*p2;
+            p2 = -9942246.505077641195658377899+xsq*p2;
+            p2 = -4435757.816794127857114720794+xsq*p2;
+            q2 = 1.0;
+            q2 = -1455.009440190496182453565068+xsq*q2;
+            q2 = -107263.8599110382011903063867+xsq*q2;
+            q2 = -1511809.506634160881644546358+xsq*q2;
+            q2 = -6585339.479723087072826915069+xsq*q2;
+            q2 = -9934124.389934585658967556309+xsq*q2;
+            q2 = -4435757.816794127856828016962+xsq*q2;
+            p3 = 35.26513384663603218592175580;
+            p3 = 1706.375429020768002061283546+xsq*p3;
+            p3 = 18494.26287322386679652009819+xsq*p3;
+            p3 = 66178.83658127083517939992166+xsq*p3;
+            p3 = 85145.16067533570196555001171+xsq*p3;
+            p3 = 33220.91340985722351859704442+xsq*p3;
+            q3 = 1.0;
+            q3 = 863.8367769604990967475517183+xsq*q3;
+            q3 = 37890.22974577220264142952256+xsq*q3;
+            q3 = 400294.4358226697511708610813+xsq*q3;
+            q3 = 1419460.669603720892855755253+xsq*q3;
+            q3 = 1819458.042243997298924553839+xsq*q3;
+            q3 = 708712.8194102874357377502472+xsq*q3;
+            pzero = p2/q2;
+            qzero = 8*p3/q3/x;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/betaf.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/betaf.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/betaf.cs	(revision 2645)
@@ -0,0 +1,96 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class betaf
+    {
+        /*************************************************************************
+        Beta function
+
+
+                          -     -
+                         | (a) | (b)
+        beta( a, b )  =  -----------.
+                            -
+                           | (a+b)
+
+        For large arguments the logarithm of the function is
+        evaluated using lgam(), then exponentiated.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE       0,30       30000       8.1e-14     1.1e-14
+
+        Cephes Math Library Release 2.0:  April, 1987
+        Copyright 1984, 1987 by Stephen L. Moshier
+        *************************************************************************/
+        public static double beta(double a,
+            double b)
+        {
+            double result = 0;
+            double y = 0;
+            double sg = 0;
+            double s = 0;
+
+            sg = 1;
+            System.Diagnostics.Debug.Assert((double)(a)>(double)(0) | (double)(a)!=(double)((int)Math.Floor(a)), "Overflow in Beta");
+            System.Diagnostics.Debug.Assert((double)(b)>(double)(0) | (double)(b)!=(double)((int)Math.Floor(b)), "Overflow in Beta");
+            y = a+b;
+            if( (double)(Math.Abs(y))>(double)(171.624376956302725) )
+            {
+                y = gammafunc.lngamma(y, ref s);
+                sg = sg*s;
+                y = gammafunc.lngamma(b, ref s)-y;
+                sg = sg*s;
+                y = gammafunc.lngamma(a, ref s)+y;
+                sg = sg*s;
+                System.Diagnostics.Debug.Assert((double)(y)<=(double)(Math.Log(AP.Math.MaxRealNumber)), "Overflow in Beta");
+                result = sg*Math.Exp(y);
+                return result;
+            }
+            y = gammafunc.gamma(y);
+            System.Diagnostics.Debug.Assert((double)(y)!=(double)(0), "Overflow in Beta");
+            if( (double)(a)>(double)(b) )
+            {
+                y = gammafunc.gamma(a)/y;
+                y = y*gammafunc.gamma(b);
+            }
+            else
+            {
+                y = gammafunc.gamma(b)/y;
+                y = y*gammafunc.gamma(a);
+            }
+            result = y;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bidiagonal.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bidiagonal.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/bidiagonal.cs	(revision 2645)
@@ -0,0 +1,1422 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class bidiagonal
+    {
+        /*************************************************************************
+        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, B is the  lower  bidiagonal  MxN  matrix  and  is  stored  in  the
+        corresponding   elements  of  matrix  A.  Q = H(0)*H(1)*...*H(m-2),  where
+        H(i) = 1 - tau*v*v', tau is stored in TauQ, v(0:i)=0, v(i+1)=1, v(i+2:m-1)
+        is    stored    in   elements   A(i+2:m-1,i).    P = G(0)*G(1)*...*G(m-1),
+        G(i) = 1-tau*u*u', tau is stored in  TauP,  u(0:i-1)=0, u(i)=1, u(i+1:n-1)
+        is stored in A(i,i+1:n-1).
+
+        EXAMPLE:
+
+        m=6, n=5 (m > n):               m=5, n=6 (m < n):
+
+        (  d   e   u1  u1  u1 )         (  d   u1  u1  u1  u1  u1 )
+        (  v1  d   e   u2  u2 )         (  e   d   u2  u2  u2  u2 )
+        (  v1  v2  d   e   u3 )         (  v1  e   d   u3  u3  u3 )
+        (  v1  v2  v3  d   e  )         (  v1  v2  e   d   u4  u4 )
+        (  v1  v2  v3  v4  d  )         (  v1  v2  v3  e   d   u5 )
+        (  v1  v2  v3  v4  v5 )
+
+        Here vi and ui are vectors which form H(i) and G(i), and d and e -
+        are the diagonal and off-diagonal elements of matrix B.
+        *************************************************************************/
+        public static void rmatrixbd(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tauq,
+            ref double[] taup)
+        {
+            double[] work = new double[0];
+            double[] t = new double[0];
+            int minmn = 0;
+            int maxmn = 0;
+            int i = 0;
+            int j = 0;
+            double ltau = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            
+            //
+            // Prepare
+            //
+            if( n<=0 | m<=0 )
+            {
+                return;
+            }
+            minmn = Math.Min(m, n);
+            maxmn = Math.Max(m, n);
+            work = new double[maxmn+1];
+            t = new double[maxmn+1];
+            if( m>=n )
+            {
+                tauq = new double[n-1+1];
+                taup = new double[n-1+1];
+            }
+            else
+            {
+                tauq = new double[m-1+1];
+                taup = new double[m-1+1];
+            }
+            if( m>=n )
+            {
+                
+                //
+                // Reduce to upper bidiagonal form
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector H(i) to annihilate A(i+1:m-1,i)
+                    //
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=m-i;i_++)
+                    {
+                        t[i_] = a[i_+i1_,i];
+                    }
+                    reflections.generatereflection(ref t, m-i, ref ltau);
+                    tauq[i] = ltau;
+                    i1_ = (1) - (i);
+                    for(i_=i; i_<=m-1;i_++)
+                    {
+                        a[i_,i] = t[i_+i1_];
+                    }
+                    t[1] = 1;
+                    
+                    //
+                    // Apply H(i) to A(i:m-1,i+1:n-1) from the left
+                    //
+                    reflections.applyreflectionfromtheleft(ref a, ltau, ref t, i, m-1, i+1, n-1, ref work);
+                    if( i<n-1 )
+                    {
+                        
+                        //
+                        // Generate elementary reflector G(i) to annihilate
+                        // A(i,i+2:n-1)
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t[i_] = a[i,i_+i1_];
+                        }
+                        reflections.generatereflection(ref t, n-1-i, ref ltau);
+                        taup[i] = ltau;
+                        i1_ = (1) - (i+1);
+                        for(i_=i+1; i_<=n-1;i_++)
+                        {
+                            a[i,i_] = t[i_+i1_];
+                        }
+                        t[1] = 1;
+                        
+                        //
+                        // Apply G(i) to A(i+1:m-1,i+1:n-1) from the right
+                        //
+                        reflections.applyreflectionfromtheright(ref a, ltau, ref t, i+1, m-1, i+1, n-1, ref work);
+                    }
+                    else
+                    {
+                        taup[i] = 0;
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Reduce to lower bidiagonal form
+                //
+                for(i=0; i<=m-1; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector G(i) to annihilate A(i,i+1:n-1)
+                    //
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=n-i;i_++)
+                    {
+                        t[i_] = a[i,i_+i1_];
+                    }
+                    reflections.generatereflection(ref t, n-i, ref ltau);
+                    taup[i] = ltau;
+                    i1_ = (1) - (i);
+                    for(i_=i; i_<=n-1;i_++)
+                    {
+                        a[i,i_] = t[i_+i1_];
+                    }
+                    t[1] = 1;
+                    
+                    //
+                    // Apply G(i) to A(i+1:m-1,i:n-1) from the right
+                    //
+                    reflections.applyreflectionfromtheright(ref a, ltau, ref t, i+1, m-1, i, n-1, ref work);
+                    if( i<m-1 )
+                    {
+                        
+                        //
+                        // Generate elementary reflector H(i) to annihilate
+                        // A(i+2:m-1,i)
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=m-1-i;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        reflections.generatereflection(ref t, m-1-i, ref ltau);
+                        tauq[i] = ltau;
+                        i1_ = (1) - (i+1);
+                        for(i_=i+1; i_<=m-1;i_++)
+                        {
+                            a[i_,i] = t[i_+i1_];
+                        }
+                        t[1] = 1;
+                        
+                        //
+                        // Apply H(i) to A(i+1:m-1,i+1:n-1) from the left
+                        //
+                        reflections.applyreflectionfromtheleft(ref a, ltau, ref t, i+1, m-1, i+1, n-1, ref work);
+                    }
+                    else
+                    {
+                        tauq[i] = 0;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixbdunpackq(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] tauq,
+            int qcolumns,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+
+            System.Diagnostics.Debug.Assert(qcolumns<=m, "RMatrixBDUnpackQ: QColumns>M!");
+            System.Diagnostics.Debug.Assert(qcolumns>=0, "RMatrixBDUnpackQ: QColumns<0!");
+            if( m==0 | n==0 | qcolumns==0 )
+            {
+                return;
+            }
+            
+            //
+            // prepare Q
+            //
+            q = new double[m-1+1, qcolumns-1+1];
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=qcolumns-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // Calculate
+            //
+            rmatrixbdmultiplybyq(ref qp, m, n, ref tauq, ref q, m, qcolumns, false, false);
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixbdmultiplybyq(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] tauq,
+            ref double[,] z,
+            int zrows,
+            int zcolumns,
+            bool fromtheright,
+            bool dotranspose)
+        {
+            int i = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int istep = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int mx = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( m<=0 | n<=0 | zrows<=0 | zcolumns<=0 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(fromtheright & zcolumns==m | !fromtheright & zrows==m, "RMatrixBDMultiplyByQ: incorrect Z size!");
+            
+            //
+            // init
+            //
+            mx = Math.Max(m, n);
+            mx = Math.Max(mx, zrows);
+            mx = Math.Max(mx, zcolumns);
+            v = new double[mx+1];
+            work = new double[mx+1];
+            if( m>=n )
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = 0;
+                    i2 = n-1;
+                    istep = +1;
+                }
+                else
+                {
+                    i1 = n-1;
+                    i2 = 0;
+                    istep = -1;
+                }
+                if( dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                i = i1;
+                do
+                {
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=m-i;i_++)
+                    {
+                        v[i_] = qp[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    if( fromtheright )
+                    {
+                        reflections.applyreflectionfromtheright(ref z, tauq[i], ref v, 0, zrows-1, i, m-1, ref work);
+                    }
+                    else
+                    {
+                        reflections.applyreflectionfromtheleft(ref z, tauq[i], ref v, i, m-1, 0, zcolumns-1, ref 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;
+                }
+                if( dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                if( m-1>0 )
+                {
+                    i = i1;
+                    do
+                    {
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=m-i-1;i_++)
+                        {
+                            v[i_] = qp[i_+i1_,i];
+                        }
+                        v[1] = 1;
+                        if( fromtheright )
+                        {
+                            reflections.applyreflectionfromtheright(ref z, tauq[i], ref v, 0, zrows-1, i+1, m-1, ref work);
+                        }
+                        else
+                        {
+                            reflections.applyreflectionfromtheleft(ref z, tauq[i], ref v, i+1, m-1, 0, zcolumns-1, ref 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.
+
+          -- ALGLIB --
+             Copyright 2005-2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixbdunpackpt(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] taup,
+            int ptrows,
+            ref double[,] pt)
+        {
+            int i = 0;
+            int j = 0;
+
+            System.Diagnostics.Debug.Assert(ptrows<=n, "RMatrixBDUnpackPT: PTRows>N!");
+            System.Diagnostics.Debug.Assert(ptrows>=0, "RMatrixBDUnpackPT: PTRows<0!");
+            if( m==0 | n==0 | ptrows==0 )
+            {
+                return;
+            }
+            
+            //
+            // prepare PT
+            //
+            pt = new double[ptrows-1+1, n-1+1];
+            for(i=0; i<=ptrows-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        pt[i,j] = 1;
+                    }
+                    else
+                    {
+                        pt[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // Calculate
+            //
+            rmatrixbdmultiplybyp(ref qp, m, n, ref taup, ref pt, ptrows, n, true, true);
+        }
+
+
+        /*************************************************************************
+        Multiplication by matrix P which reduces matrix A to  bidiagonal form.
+
+        The algorithm allows pre- or post-multiply by P or P'.
+
+        Input parameters:
+            QP          -   matrices Q and P in compact form.
+                            Output of RMatrixBD subroutine.
+            M           -   number of rows in matrix A.
+            N           -   number of columns in matrix A.
+            TAUP        -   scalar factors which are used to form P.
+                            Output of RMatrixBD subroutine.
+            Z           -   multiplied matrix.
+                            Array whose indexes range within [0..ZRows-1,0..ZColumns-1].
+            ZRows       -   number of rows in matrix Z. If FromTheRight=False,
+                            ZRows=N, otherwise ZRows can be arbitrary.
+            ZColumns    -   number of columns in matrix Z. If FromTheRight=True,
+                            ZColumns=N, otherwise ZColumns can be arbitrary.
+            FromTheRight -  pre- or post-multiply.
+            DoTranspose -   multiply by P or P'.
+
+        Output parameters:
+            Z - product of Z and P.
+                        Array whose indexes range within [0..ZRows-1,0..ZColumns-1].
+                        If ZRows=0 or ZColumns=0, the array is not modified.
+
+          -- ALGLIB --
+             Copyright 2005-2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixbdmultiplybyp(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] taup,
+            ref double[,] z,
+            int zrows,
+            int zcolumns,
+            bool fromtheright,
+            bool dotranspose)
+        {
+            int i = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int mx = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int istep = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( m<=0 | n<=0 | zrows<=0 | zcolumns<=0 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(fromtheright & zcolumns==n | !fromtheright & zrows==n, "RMatrixBDMultiplyByP: incorrect Z size!");
+            
+            //
+            // init
+            //
+            mx = Math.Max(m, n);
+            mx = Math.Max(mx, zrows);
+            mx = Math.Max(mx, zcolumns);
+            v = new double[mx+1];
+            work = new double[mx+1];
+            v = new double[mx+1];
+            work = new double[mx+1];
+            if( m>=n )
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = n-2;
+                    i2 = 0;
+                    istep = -1;
+                }
+                else
+                {
+                    i1 = 0;
+                    i2 = n-2;
+                    istep = +1;
+                }
+                if( !dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                if( n-1>0 )
+                {
+                    i = i1;
+                    do
+                    {
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-1-i;i_++)
+                        {
+                            v[i_] = qp[i,i_+i1_];
+                        }
+                        v[1] = 1;
+                        if( fromtheright )
+                        {
+                            reflections.applyreflectionfromtheright(ref z, taup[i], ref v, 0, zrows-1, i+1, n-1, ref work);
+                        }
+                        else
+                        {
+                            reflections.applyreflectionfromtheleft(ref z, taup[i], ref v, i+1, n-1, 0, zcolumns-1, ref work);
+                        }
+                        i = i+istep;
+                    }
+                    while( i!=i2+istep );
+                }
+            }
+            else
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = m-1;
+                    i2 = 0;
+                    istep = -1;
+                }
+                else
+                {
+                    i1 = 0;
+                    i2 = m-1;
+                    istep = +1;
+                }
+                if( !dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                i = i1;
+                do
+                {
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=n-i;i_++)
+                    {
+                        v[i_] = qp[i,i_+i1_];
+                    }
+                    v[1] = 1;
+                    if( fromtheright )
+                    {
+                        reflections.applyreflectionfromtheright(ref z, taup[i], ref v, 0, zrows-1, i, n-1, ref work);
+                    }
+                    else
+                    {
+                        reflections.applyreflectionfromtheleft(ref z, taup[i], ref v, i, n-1, 0, zcolumns-1, ref work);
+                    }
+                    i = i+istep;
+                }
+                while( i!=i2+istep );
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacking of the main and secondary diagonals of bidiagonal decomposition
+        of matrix A.
+
+        Input parameters:
+            B   -   output of RMatrixBD subroutine.
+            M   -   number of rows in matrix B.
+            N   -   number of columns in matrix B.
+
+        Output parameters:
+            IsUpper -   True, if the matrix is upper bidiagonal.
+                        otherwise IsUpper is False.
+            D       -   the main diagonal.
+                        Array whose index ranges within [0..Min(M,N)-1].
+            E       -   the secondary diagonal (upper or lower, depending on
+                        the value of IsUpper).
+                        Array index ranges within [0..Min(M,N)-1], the last
+                        element is not used.
+
+          -- ALGLIB --
+             Copyright 2005-2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixbdunpackdiagonals(ref double[,] b,
+            int m,
+            int n,
+            ref bool isupper,
+            ref double[] d,
+            ref double[] e)
+        {
+            int i = 0;
+
+            isupper = m>=n;
+            if( m<=0 | n<=0 )
+            {
+                return;
+            }
+            if( isupper )
+            {
+                d = new double[n-1+1];
+                e = new double[n-1+1];
+                for(i=0; i<=n-2; i++)
+                {
+                    d[i] = b[i,i];
+                    e[i] = b[i,i+1];
+                }
+                d[n-1] = b[n-1,n-1];
+            }
+            else
+            {
+                d = new double[m-1+1];
+                e = new double[m-1+1];
+                for(i=0; i<=m-2; i++)
+                {
+                    d[i] = b[i,i];
+                    e[i] = b[i+1,i];
+                }
+                d[m-1] = b[m-1,m-1];
+            }
+        }
+
+
+        public static void tobidiagonal(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tauq,
+            ref double[] taup)
+        {
+            double[] work = new double[0];
+            double[] t = new double[0];
+            int minmn = 0;
+            int maxmn = 0;
+            int i = 0;
+            double ltau = 0;
+            int mmip1 = 0;
+            int nmi = 0;
+            int ip1 = 0;
+            int nmip1 = 0;
+            int mmi = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            minmn = Math.Min(m, n);
+            maxmn = Math.Max(m, n);
+            work = new double[maxmn+1];
+            t = new double[maxmn+1];
+            taup = new double[minmn+1];
+            tauq = new double[minmn+1];
+            if( m>=n )
+            {
+                
+                //
+                // Reduce to upper bidiagonal form
+                //
+                for(i=1; i<=n; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector H(i) to annihilate A(i+1:m,i)
+                    //
+                    mmip1 = m-i+1;
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=mmip1;i_++)
+                    {
+                        t[i_] = a[i_+i1_,i];
+                    }
+                    reflections.generatereflection(ref t, mmip1, ref ltau);
+                    tauq[i] = ltau;
+                    i1_ = (1) - (i);
+                    for(i_=i; i_<=m;i_++)
+                    {
+                        a[i_,i] = t[i_+i1_];
+                    }
+                    t[1] = 1;
+                    
+                    //
+                    // Apply H(i) to A(i:m,i+1:n) from the left
+                    //
+                    reflections.applyreflectionfromtheleft(ref a, ltau, ref t, i, m, i+1, n, ref work);
+                    if( i<n )
+                    {
+                        
+                        //
+                        // Generate elementary reflector G(i) to annihilate
+                        // A(i,i+2:n)
+                        //
+                        nmi = n-i;
+                        ip1 = i+1;
+                        i1_ = (ip1) - (1);
+                        for(i_=1; i_<=nmi;i_++)
+                        {
+                            t[i_] = a[i,i_+i1_];
+                        }
+                        reflections.generatereflection(ref t, nmi, ref ltau);
+                        taup[i] = ltau;
+                        i1_ = (1) - (ip1);
+                        for(i_=ip1; i_<=n;i_++)
+                        {
+                            a[i,i_] = t[i_+i1_];
+                        }
+                        t[1] = 1;
+                        
+                        //
+                        // Apply G(i) to A(i+1:m,i+1:n) from the right
+                        //
+                        reflections.applyreflectionfromtheright(ref a, ltau, ref t, i+1, m, i+1, n, ref work);
+                    }
+                    else
+                    {
+                        taup[i] = 0;
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Reduce to lower bidiagonal form
+                //
+                for(i=1; i<=m; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector G(i) to annihilate A(i,i+1:n)
+                    //
+                    nmip1 = n-i+1;
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=nmip1;i_++)
+                    {
+                        t[i_] = a[i,i_+i1_];
+                    }
+                    reflections.generatereflection(ref t, nmip1, ref ltau);
+                    taup[i] = ltau;
+                    i1_ = (1) - (i);
+                    for(i_=i; i_<=n;i_++)
+                    {
+                        a[i,i_] = t[i_+i1_];
+                    }
+                    t[1] = 1;
+                    
+                    //
+                    // Apply G(i) to A(i+1:m,i:n) from the right
+                    //
+                    reflections.applyreflectionfromtheright(ref a, ltau, ref t, i+1, m, i, n, ref work);
+                    if( i<m )
+                    {
+                        
+                        //
+                        // Generate elementary reflector H(i) to annihilate
+                        // A(i+2:m,i)
+                        //
+                        mmi = m-i;
+                        ip1 = i+1;
+                        i1_ = (ip1) - (1);
+                        for(i_=1; i_<=mmi;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        reflections.generatereflection(ref t, mmi, ref ltau);
+                        tauq[i] = ltau;
+                        i1_ = (1) - (ip1);
+                        for(i_=ip1; i_<=m;i_++)
+                        {
+                            a[i_,i] = t[i_+i1_];
+                        }
+                        t[1] = 1;
+                        
+                        //
+                        // Apply H(i) to A(i+1:m,i+1:n) from the left
+                        //
+                        reflections.applyreflectionfromtheleft(ref a, ltau, ref t, i+1, m, i+1, n, ref work);
+                    }
+                    else
+                    {
+                        tauq[i] = 0;
+                    }
+                }
+            }
+        }
+
+
+        public static void unpackqfrombidiagonal(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] tauq,
+            int qcolumns,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int ip1 = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qcolumns<=m, "UnpackQFromBidiagonal: QColumns>M!");
+            if( m==0 | n==0 | qcolumns==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new double[m+1, qcolumns+1];
+            v = new double[m+1];
+            work = new double[qcolumns+1];
+            
+            //
+            // prepare Q
+            //
+            for(i=1; i<=m; i++)
+            {
+                for(j=1; j<=qcolumns; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            if( m>=n )
+            {
+                for(i=Math.Min(n, qcolumns); i>=1; i--)
+                {
+                    vm = m-i+1;
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=vm;i_++)
+                    {
+                        v[i_] = qp[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    reflections.applyreflectionfromtheleft(ref q, tauq[i], ref v, i, m, 1, qcolumns, ref work);
+                }
+            }
+            else
+            {
+                for(i=Math.Min(m-1, qcolumns-1); i>=1; i--)
+                {
+                    vm = m-i;
+                    ip1 = i+1;
+                    i1_ = (ip1) - (1);
+                    for(i_=1; i_<=vm;i_++)
+                    {
+                        v[i_] = qp[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    reflections.applyreflectionfromtheleft(ref q, tauq[i], ref v, i+1, m, 1, qcolumns, ref work);
+                }
+            }
+        }
+
+
+        public static void multiplybyqfrombidiagonal(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] tauq,
+            ref double[,] z,
+            int zrows,
+            int zcolumns,
+            bool fromtheright,
+            bool dotranspose)
+        {
+            int i = 0;
+            int ip1 = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int istep = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int vm = 0;
+            int mx = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( m<=0 | n<=0 | zrows<=0 | zcolumns<=0 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(fromtheright & zcolumns==m | !fromtheright & zrows==m, "MultiplyByQFromBidiagonal: incorrect Z size!");
+            
+            //
+            // init
+            //
+            mx = Math.Max(m, n);
+            mx = Math.Max(mx, zrows);
+            mx = Math.Max(mx, zcolumns);
+            v = new double[mx+1];
+            work = new double[mx+1];
+            if( m>=n )
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = 1;
+                    i2 = n;
+                    istep = +1;
+                }
+                else
+                {
+                    i1 = n;
+                    i2 = 1;
+                    istep = -1;
+                }
+                if( dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                i = i1;
+                do
+                {
+                    vm = m-i+1;
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=vm;i_++)
+                    {
+                        v[i_] = qp[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    if( fromtheright )
+                    {
+                        reflections.applyreflectionfromtheright(ref z, tauq[i], ref v, 1, zrows, i, m, ref work);
+                    }
+                    else
+                    {
+                        reflections.applyreflectionfromtheleft(ref z, tauq[i], ref v, i, m, 1, zcolumns, ref work);
+                    }
+                    i = i+istep;
+                }
+                while( i!=i2+istep );
+            }
+            else
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = 1;
+                    i2 = m-1;
+                    istep = +1;
+                }
+                else
+                {
+                    i1 = m-1;
+                    i2 = 1;
+                    istep = -1;
+                }
+                if( dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                if( m-1>0 )
+                {
+                    i = i1;
+                    do
+                    {
+                        vm = m-i;
+                        ip1 = i+1;
+                        i1_ = (ip1) - (1);
+                        for(i_=1; i_<=vm;i_++)
+                        {
+                            v[i_] = qp[i_+i1_,i];
+                        }
+                        v[1] = 1;
+                        if( fromtheright )
+                        {
+                            reflections.applyreflectionfromtheright(ref z, tauq[i], ref v, 1, zrows, i+1, m, ref work);
+                        }
+                        else
+                        {
+                            reflections.applyreflectionfromtheleft(ref z, tauq[i], ref v, i+1, m, 1, zcolumns, ref work);
+                        }
+                        i = i+istep;
+                    }
+                    while( i!=i2+istep );
+                }
+            }
+        }
+
+
+        public static void unpackptfrombidiagonal(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] taup,
+            int ptrows,
+            ref double[,] pt)
+        {
+            int i = 0;
+            int j = 0;
+            int ip1 = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(ptrows<=n, "UnpackPTFromBidiagonal: PTRows>N!");
+            if( m==0 | n==0 | ptrows==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            pt = new double[ptrows+1, n+1];
+            v = new double[n+1];
+            work = new double[ptrows+1];
+            
+            //
+            // prepare PT
+            //
+            for(i=1; i<=ptrows; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( i==j )
+                    {
+                        pt[i,j] = 1;
+                    }
+                    else
+                    {
+                        pt[i,j] = 0;
+                    }
+                }
+            }
+            if( m>=n )
+            {
+                for(i=Math.Min(n-1, ptrows-1); i>=1; i--)
+                {
+                    vm = n-i;
+                    ip1 = i+1;
+                    i1_ = (ip1) - (1);
+                    for(i_=1; i_<=vm;i_++)
+                    {
+                        v[i_] = qp[i,i_+i1_];
+                    }
+                    v[1] = 1;
+                    reflections.applyreflectionfromtheright(ref pt, taup[i], ref v, 1, ptrows, i+1, n, ref work);
+                }
+            }
+            else
+            {
+                for(i=Math.Min(m, ptrows); i>=1; i--)
+                {
+                    vm = n-i+1;
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=vm;i_++)
+                    {
+                        v[i_] = qp[i,i_+i1_];
+                    }
+                    v[1] = 1;
+                    reflections.applyreflectionfromtheright(ref pt, taup[i], ref v, 1, ptrows, i, n, ref work);
+                }
+            }
+        }
+
+
+        public static void multiplybypfrombidiagonal(ref double[,] qp,
+            int m,
+            int n,
+            ref double[] taup,
+            ref double[,] z,
+            int zrows,
+            int zcolumns,
+            bool fromtheright,
+            bool dotranspose)
+        {
+            int i = 0;
+            int ip1 = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int vm = 0;
+            int mx = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int istep = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( m<=0 | n<=0 | zrows<=0 | zcolumns<=0 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(fromtheright & zcolumns==n | !fromtheright & zrows==n, "MultiplyByQFromBidiagonal: incorrect Z size!");
+            
+            //
+            // init
+            //
+            mx = Math.Max(m, n);
+            mx = Math.Max(mx, zrows);
+            mx = Math.Max(mx, zcolumns);
+            v = new double[mx+1];
+            work = new double[mx+1];
+            v = new double[mx+1];
+            work = new double[mx+1];
+            if( m>=n )
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = n-1;
+                    i2 = 1;
+                    istep = -1;
+                }
+                else
+                {
+                    i1 = 1;
+                    i2 = n-1;
+                    istep = +1;
+                }
+                if( !dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                if( n-1>0 )
+                {
+                    i = i1;
+                    do
+                    {
+                        vm = n-i;
+                        ip1 = i+1;
+                        i1_ = (ip1) - (1);
+                        for(i_=1; i_<=vm;i_++)
+                        {
+                            v[i_] = qp[i,i_+i1_];
+                        }
+                        v[1] = 1;
+                        if( fromtheright )
+                        {
+                            reflections.applyreflectionfromtheright(ref z, taup[i], ref v, 1, zrows, i+1, n, ref work);
+                        }
+                        else
+                        {
+                            reflections.applyreflectionfromtheleft(ref z, taup[i], ref v, i+1, n, 1, zcolumns, ref work);
+                        }
+                        i = i+istep;
+                    }
+                    while( i!=i2+istep );
+                }
+            }
+            else
+            {
+                
+                //
+                // setup
+                //
+                if( fromtheright )
+                {
+                    i1 = m;
+                    i2 = 1;
+                    istep = -1;
+                }
+                else
+                {
+                    i1 = 1;
+                    i2 = m;
+                    istep = +1;
+                }
+                if( !dotranspose )
+                {
+                    i = i1;
+                    i1 = i2;
+                    i2 = i;
+                    istep = -istep;
+                }
+                
+                //
+                // Process
+                //
+                i = i1;
+                do
+                {
+                    vm = n-i+1;
+                    i1_ = (i) - (1);
+                    for(i_=1; i_<=vm;i_++)
+                    {
+                        v[i_] = qp[i,i_+i1_];
+                    }
+                    v[1] = 1;
+                    if( fromtheright )
+                    {
+                        reflections.applyreflectionfromtheright(ref z, taup[i], ref v, 1, zrows, i, n, ref work);
+                    }
+                    else
+                    {
+                        reflections.applyreflectionfromtheleft(ref z, taup[i], ref v, i, n, 1, zcolumns, ref work);
+                    }
+                    i = i+istep;
+                }
+                while( i!=i2+istep );
+            }
+        }
+
+
+        public static void unpackdiagonalsfrombidiagonal(ref double[,] b,
+            int m,
+            int n,
+            ref bool isupper,
+            ref double[] d,
+            ref double[] e)
+        {
+            int i = 0;
+
+            isupper = m>=n;
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            if( isupper )
+            {
+                d = new double[n+1];
+                e = new double[n+1];
+                for(i=1; i<=n-1; i++)
+                {
+                    d[i] = b[i,i];
+                    e[i] = b[i,i+1];
+                }
+                d[n] = b[n,n];
+            }
+            else
+            {
+                d = new double[m+1];
+                e = new double[m+1];
+                for(i=1; i<=m-1; i++)
+                {
+                    d[i] = b[i,i];
+                    e[i] = b[i+1,i];
+                }
+                d[m] = b[m,m];
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/binomialdistr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/binomialdistr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/binomialdistr.cs	(revision 2645)
@@ -0,0 +1,242 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class binomialdistr
+    {
+        /*************************************************************************
+        Binomial distribution
+
+        Returns the sum of the terms 0 through k of the Binomial
+        probability density:
+
+          k
+          --  ( n )   j      n-j
+          >   (   )  p  (1-p)
+          --  ( j )
+         j=0
+
+        The terms are not summed directly; instead the incomplete
+        beta integral is employed, according to the formula
+
+        y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ).
+
+        The arguments must be positive, with p ranging from 0 to 1.
+
+        ACCURACY:
+
+        Tested at random points (a,b,p), with p between 0 and 1.
+
+                      a,b                     Relative error:
+        arithmetic  domain     # trials      peak         rms
+         For p between 0.001 and 1:
+           IEEE     0,100       100000      4.3e-15     2.6e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double binomialdistribution(int k,
+            int n,
+            double p)
+        {
+            double result = 0;
+            double dk = 0;
+            double dn = 0;
+
+            System.Diagnostics.Debug.Assert((double)(p)>=(double)(0) & (double)(p)<=(double)(1), "Domain error in BinomialDistribution");
+            System.Diagnostics.Debug.Assert(k>=-1 & k<=n, "Domain error in BinomialDistribution");
+            if( k==-1 )
+            {
+                result = 0;
+                return result;
+            }
+            if( k==n )
+            {
+                result = 1;
+                return result;
+            }
+            dn = n-k;
+            if( k==0 )
+            {
+                dk = Math.Pow(1.0-p, dn);
+            }
+            else
+            {
+                dk = k+1;
+                dk = ibetaf.incompletebeta(dn, dk, 1.0-p);
+            }
+            result = dk;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complemented binomial distribution
+
+        Returns the sum of the terms k+1 through n of the Binomial
+        probability density:
+
+          n
+          --  ( n )   j      n-j
+          >   (   )  p  (1-p)
+          --  ( j )
+         j=k+1
+
+        The terms are not summed directly; instead the incomplete
+        beta integral is employed, according to the formula
+
+        y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ).
+
+        The arguments must be positive, with p ranging from 0 to 1.
+
+        ACCURACY:
+
+        Tested at random points (a,b,p).
+
+                      a,b                     Relative error:
+        arithmetic  domain     # trials      peak         rms
+         For p between 0.001 and 1:
+           IEEE     0,100       100000      6.7e-15     8.2e-16
+         For p between 0 and .001:
+           IEEE     0,100       100000      1.5e-13     2.7e-15
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double binomialcdistribution(int k,
+            int n,
+            double p)
+        {
+            double result = 0;
+            double dk = 0;
+            double dn = 0;
+
+            System.Diagnostics.Debug.Assert((double)(p)>=(double)(0) & (double)(p)<=(double)(1), "Domain error in BinomialDistributionC");
+            System.Diagnostics.Debug.Assert(k>=-1 & k<=n, "Domain error in BinomialDistributionC");
+            if( k==-1 )
+            {
+                result = 1;
+                return result;
+            }
+            if( k==n )
+            {
+                result = 0;
+                return result;
+            }
+            dn = n-k;
+            if( k==0 )
+            {
+                if( (double)(p)<(double)(0.01) )
+                {
+                    dk = -nearunityunit.expm1(dn*nearunityunit.log1p(-p));
+                }
+                else
+                {
+                    dk = 1.0-Math.Pow(1.0-p, dn);
+                }
+            }
+            else
+            {
+                dk = k+1;
+                dk = ibetaf.incompletebeta(dk, dn, p);
+            }
+            result = dk;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse binomial distribution
+
+        Finds the event probability p such that the sum of the
+        terms 0 through k of the Binomial probability density
+        is equal to the given cumulative probability y.
+
+        This is accomplished using the inverse beta integral
+        function and the relation
+
+        1 - p = incbi( n-k, k+1, y ).
+
+        ACCURACY:
+
+        Tested at random points (a,b,p).
+
+                      a,b                     Relative error:
+        arithmetic  domain     # trials      peak         rms
+         For p between 0.001 and 1:
+           IEEE     0,100       100000      2.3e-14     6.4e-16
+           IEEE     0,10000     100000      6.6e-12     1.2e-13
+         For p between 10^-6 and 0.001:
+           IEEE     0,100       100000      2.0e-12     1.3e-14
+           IEEE     0,10000     100000      1.5e-12     3.2e-14
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invbinomialdistribution(int k,
+            int n,
+            double y)
+        {
+            double result = 0;
+            double dk = 0;
+            double dn = 0;
+            double p = 0;
+
+            System.Diagnostics.Debug.Assert(k>=0 & k<n, "Domain error in InvBinomialDistribution");
+            dn = n-k;
+            if( k==0 )
+            {
+                if( (double)(y)>(double)(0.8) )
+                {
+                    p = -nearunityunit.expm1(nearunityunit.log1p(y-1.0)/dn);
+                }
+                else
+                {
+                    p = 1.0-Math.Pow(y, 1.0/dn);
+                }
+            }
+            else
+            {
+                dk = k+1;
+                p = ibetaf.incompletebeta(dn, dk, 0.5);
+                if( (double)(p)>(double)(0.5) )
+                {
+                    p = ibetaf.invincompletebeta(dk, dn, 1.0-y);
+                }
+                else
+                {
+                    p = 1.0-ibetaf.invincompletebeta(dn, dk, y);
+                }
+            }
+            result = p;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/blas.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/blas.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/blas.cs	(revision 2645)
@@ -0,0 +1,660 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class blas
+    {
+        public static double vectornorm2(ref double[] x,
+            int i1,
+            int i2)
+        {
+            double result = 0;
+            int n = 0;
+            int ix = 0;
+            double absxi = 0;
+            double scl = 0;
+            double ssq = 0;
+
+            n = i2-i1+1;
+            if( n<1 )
+            {
+                result = 0;
+                return result;
+            }
+            if( n==1 )
+            {
+                result = Math.Abs(x[i1]);
+                return result;
+            }
+            scl = 0;
+            ssq = 1;
+            for(ix=i1; ix<=i2; ix++)
+            {
+                if( (double)(x[ix])!=(double)(0) )
+                {
+                    absxi = Math.Abs(x[ix]);
+                    if( (double)(scl)<(double)(absxi) )
+                    {
+                        ssq = 1+ssq*AP.Math.Sqr(scl/absxi);
+                        scl = absxi;
+                    }
+                    else
+                    {
+                        ssq = ssq+AP.Math.Sqr(absxi/scl);
+                    }
+                }
+            }
+            result = scl*Math.Sqrt(ssq);
+            return result;
+        }
+
+
+        public static int vectoridxabsmax(ref double[] x,
+            int i1,
+            int i2)
+        {
+            int result = 0;
+            int i = 0;
+            double a = 0;
+
+            result = i1;
+            a = Math.Abs(x[result]);
+            for(i=i1+1; i<=i2; i++)
+            {
+                if( (double)(Math.Abs(x[i]))>(double)(Math.Abs(x[result])) )
+                {
+                    result = i;
+                }
+            }
+            return result;
+        }
+
+
+        public static int columnidxabsmax(ref double[,] x,
+            int i1,
+            int i2,
+            int j)
+        {
+            int result = 0;
+            int i = 0;
+            double a = 0;
+
+            result = i1;
+            a = Math.Abs(x[result,j]);
+            for(i=i1+1; i<=i2; i++)
+            {
+                if( (double)(Math.Abs(x[i,j]))>(double)(Math.Abs(x[result,j])) )
+                {
+                    result = i;
+                }
+            }
+            return result;
+        }
+
+
+        public static int rowidxabsmax(ref double[,] x,
+            int j1,
+            int j2,
+            int i)
+        {
+            int result = 0;
+            int j = 0;
+            double a = 0;
+
+            result = j1;
+            a = Math.Abs(x[i,result]);
+            for(j=j1+1; j<=j2; j++)
+            {
+                if( (double)(Math.Abs(x[i,j]))>(double)(Math.Abs(x[i,result])) )
+                {
+                    result = j;
+                }
+            }
+            return result;
+        }
+
+
+        public static double upperhessenberg1norm(ref double[,] a,
+            int i1,
+            int i2,
+            int j1,
+            int j2,
+            ref double[] work)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+
+            System.Diagnostics.Debug.Assert(i2-i1==j2-j1, "UpperHessenberg1Norm: I2-I1<>J2-J1!");
+            for(j=j1; j<=j2; j++)
+            {
+                work[j] = 0;
+            }
+            for(i=i1; i<=i2; i++)
+            {
+                for(j=Math.Max(j1, j1+i-i1-1); j<=j2; j++)
+                {
+                    work[j] = work[j]+Math.Abs(a[i,j]);
+                }
+            }
+            result = 0;
+            for(j=j1; j<=j2; j++)
+            {
+                result = Math.Max(result, work[j]);
+            }
+            return result;
+        }
+
+
+        public static void copymatrix(ref double[,] a,
+            int is1,
+            int is2,
+            int js1,
+            int js2,
+            ref double[,] b,
+            int id1,
+            int id2,
+            int jd1,
+            int jd2)
+        {
+            int isrc = 0;
+            int idst = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( is1>is2 | js1>js2 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(is2-is1==id2-id1, "CopyMatrix: different sizes!");
+            System.Diagnostics.Debug.Assert(js2-js1==jd2-jd1, "CopyMatrix: different sizes!");
+            for(isrc=is1; isrc<=is2; isrc++)
+            {
+                idst = isrc-is1+id1;
+                i1_ = (js1) - (jd1);
+                for(i_=jd1; i_<=jd2;i_++)
+                {
+                    b[idst,i_] = a[isrc,i_+i1_];
+                }
+            }
+        }
+
+
+        public static void inplacetranspose(ref double[,] a,
+            int i1,
+            int i2,
+            int j1,
+            int j2,
+            ref double[] work)
+        {
+            int i = 0;
+            int j = 0;
+            int ips = 0;
+            int jps = 0;
+            int l = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( i1>i2 | j1>j2 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(i1-i2==j1-j2, "InplaceTranspose error: incorrect array size!");
+            for(i=i1; i<=i2-1; i++)
+            {
+                j = j1+i-i1;
+                ips = i+1;
+                jps = j1+ips-i1;
+                l = i2-i;
+                i1_ = (ips) - (1);
+                for(i_=1; i_<=l;i_++)
+                {
+                    work[i_] = a[i_+i1_,j];
+                }
+                i1_ = (jps) - (ips);
+                for(i_=ips; i_<=i2;i_++)
+                {
+                    a[i_,j] = a[i,i_+i1_];
+                }
+                i1_ = (1) - (jps);
+                for(i_=jps; i_<=j2;i_++)
+                {
+                    a[i,i_] = work[i_+i1_];
+                }
+            }
+        }
+
+
+        public static void copyandtranspose(ref double[,] a,
+            int is1,
+            int is2,
+            int js1,
+            int js2,
+            ref double[,] b,
+            int id1,
+            int id2,
+            int jd1,
+            int jd2)
+        {
+            int isrc = 0;
+            int jdst = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( is1>is2 | js1>js2 )
+            {
+                return;
+            }
+            System.Diagnostics.Debug.Assert(is2-is1==jd2-jd1, "CopyAndTranspose: different sizes!");
+            System.Diagnostics.Debug.Assert(js2-js1==id2-id1, "CopyAndTranspose: different sizes!");
+            for(isrc=is1; isrc<=is2; isrc++)
+            {
+                jdst = isrc-is1+jd1;
+                i1_ = (js1) - (id1);
+                for(i_=id1; i_<=id2;i_++)
+                {
+                    b[i_,jdst] = a[isrc,i_+i1_];
+                }
+            }
+        }
+
+
+        public static void matrixvectormultiply(ref double[,] a,
+            int i1,
+            int i2,
+            int j1,
+            int j2,
+            bool trans,
+            ref double[] x,
+            int ix1,
+            int ix2,
+            double alpha,
+            ref double[] y,
+            int iy1,
+            int iy2,
+            double beta)
+        {
+            int i = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( !trans )
+            {
+                
+                //
+                // y := alpha*A*x + beta*y;
+                //
+                if( i1>i2 | j1>j2 )
+                {
+                    return;
+                }
+                System.Diagnostics.Debug.Assert(j2-j1==ix2-ix1, "MatrixVectorMultiply: A and X dont match!");
+                System.Diagnostics.Debug.Assert(i2-i1==iy2-iy1, "MatrixVectorMultiply: A and Y dont match!");
+                
+                //
+                // beta*y
+                //
+                if( (double)(beta)==(double)(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;
+                }
+                System.Diagnostics.Debug.Assert(i2-i1==ix2-ix1, "MatrixVectorMultiply: A and X dont match!");
+                System.Diagnostics.Debug.Assert(j2-j1==iy2-iy1, "MatrixVectorMultiply: A and Y dont match!");
+                
+                //
+                // beta*y
+                //
+                if( (double)(beta)==(double)(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_];
+                    }
+                }
+            }
+        }
+
+
+        public static double pythag2(double x,
+            double y)
+        {
+            double result = 0;
+            double w = 0;
+            double xabs = 0;
+            double yabs = 0;
+            double z = 0;
+
+            xabs = Math.Abs(x);
+            yabs = Math.Abs(y);
+            w = Math.Max(xabs, yabs);
+            z = Math.Min(xabs, yabs);
+            if( (double)(z)==(double)(0) )
+            {
+                result = w;
+            }
+            else
+            {
+                result = w*Math.Sqrt(1+AP.Math.Sqr(z/w));
+            }
+            return result;
+        }
+
+
+        public static void matrixmatrixmultiply(ref double[,] a,
+            int ai1,
+            int ai2,
+            int aj1,
+            int aj2,
+            bool transa,
+            ref double[,] b,
+            int bi1,
+            int bi2,
+            int bj1,
+            int bj2,
+            bool transb,
+            double alpha,
+            ref double[,] c,
+            int ci1,
+            int ci2,
+            int cj1,
+            int cj2,
+            double beta,
+            ref double[] work)
+        {
+            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;
+            }
+            if( !transb )
+            {
+                brows = bi2-bi1+1;
+                bcols = bj2-bj1+1;
+            }
+            else
+            {
+                brows = bj2-bj1+1;
+                bcols = bi2-bi1+1;
+            }
+            System.Diagnostics.Debug.Assert(acols==brows, "MatrixMatrixMultiply: incorrect matrix sizes!");
+            if( arows<=0 | acols<=0 | brows<=0 | bcols<=0 )
+            {
+                return;
+            }
+            crows = arows;
+            ccols = bcols;
+            
+            //
+            // Test WORK
+            //
+            i = Math.Max(arows, acols);
+            i = Math.Max(brows, i);
+            i = Math.Max(i, bcols);
+            work[1] = 0;
+            work[i] = 0;
+            
+            //
+            // Prepare C
+            //
+            if( (double)(beta)==(double)(0) )
+            {
+                for(i=ci1; i<=ci2; i++)
+                {
+                    for(j=cj1; j<=cj2; j++)
+                    {
+                        c[i,j] = 0;
+                    }
+                }
+            }
+            else
+            {
+                for(i=ci1; i<=ci2; i++)
+                {
+                    for(i_=cj1; i_<=cj2;i_++)
+                    {
+                        c[i,i_] = beta*c[i,i_];
+                    }
+                }
+            }
+            
+            //
+            // A*B
+            //
+            if( !transa & !transb )
+            {
+                for(l=ai1; l<=ai2; l++)
+                {
+                    for(r=bi1; r<=bi2; r++)
+                    {
+                        v = alpha*a[l,aj1+r-bi1];
+                        k = ci1+l-ai1;
+                        i1_ = (bj1) - (cj1);
+                        for(i_=cj1; i_<=cj2;i_++)
+                        {
+                            c[k,i_] = c[k,i_] + v*b[r,i_+i1_];
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // A*B'
+            //
+            if( !transa & transb )
+            {
+                if( arows*acols<brows*bcols )
+                {
+                    for(r=bi1; r<=bi2; r++)
+                    {
+                        for(l=ai1; l<=ai2; l++)
+                        {
+                            i1_ = (bj1)-(aj1);
+                            v = 0.0;
+                            for(i_=aj1; i_<=aj2;i_++)
+                            {
+                                v += a[l,i_]*b[r,i_+i1_];
+                            }
+                            c[ci1+l-ai1,cj1+r-bi1] = c[ci1+l-ai1,cj1+r-bi1]+alpha*v;
+                        }
+                    }
+                    return;
+                }
+                else
+                {
+                    for(l=ai1; l<=ai2; l++)
+                    {
+                        for(r=bi1; r<=bi2; r++)
+                        {
+                            i1_ = (bj1)-(aj1);
+                            v = 0.0;
+                            for(i_=aj1; i_<=aj2;i_++)
+                            {
+                                v += a[l,i_]*b[r,i_+i1_];
+                            }
+                            c[ci1+l-ai1,cj1+r-bi1] = c[ci1+l-ai1,cj1+r-bi1]+alpha*v;
+                        }
+                    }
+                    return;
+                }
+            }
+            
+            //
+            // A'*B
+            //
+            if( transa & !transb )
+            {
+                for(l=aj1; l<=aj2; l++)
+                {
+                    for(r=bi1; r<=bi2; r++)
+                    {
+                        v = alpha*a[ai1+r-bi1,l];
+                        k = ci1+l-aj1;
+                        i1_ = (bj1) - (cj1);
+                        for(i_=cj1; i_<=cj2;i_++)
+                        {
+                            c[k,i_] = c[k,i_] + v*b[r,i_+i1_];
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // A'*B'
+            //
+            if( transa & transb )
+            {
+                if( arows*acols<brows*bcols )
+                {
+                    for(r=bi1; r<=bi2; r++)
+                    {
+                        for(i=1; i<=crows; i++)
+                        {
+                            work[i] = 0.0;
+                        }
+                        for(l=ai1; l<=ai2; l++)
+                        {
+                            v = alpha*b[r,bj1+l-ai1];
+                            k = cj1+r-bi1;
+                            i1_ = (aj1) - (1);
+                            for(i_=1; i_<=crows;i_++)
+                            {
+                                work[i_] = work[i_] + v*a[l,i_+i1_];
+                            }
+                        }
+                        i1_ = (1) - (ci1);
+                        for(i_=ci1; i_<=ci2;i_++)
+                        {
+                            c[i_,k] = c[i_,k] + work[i_+i1_];
+                        }
+                    }
+                    return;
+                }
+                else
+                {
+                    for(l=aj1; l<=aj2; l++)
+                    {
+                        k = ai2-ai1+1;
+                        i1_ = (ai1) - (1);
+                        for(i_=1; i_<=k;i_++)
+                        {
+                            work[i_] = a[i_+i1_,l];
+                        }
+                        for(r=bi1; r<=bi2; r++)
+                        {
+                            i1_ = (bj1)-(1);
+                            v = 0.0;
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                v += work[i_]*b[r,i_+i1_];
+                            }
+                            c[ci1+l-aj1,cj1+r-bi1] = c[ci1+l-aj1,cj1+r-bi1]+alpha*v;
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cblas.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cblas.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cblas.cs	(revision 2645)
@@ -0,0 +1,216 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class cblas
+    {
+        public static void complexmatrixvectormultiply(ref AP.Complex[,] a,
+            int i1,
+            int i2,
+            int j1,
+            int j2,
+            bool transa,
+            bool conja,
+            ref AP.Complex[] x,
+            int ix1,
+            int ix2,
+            AP.Complex alpha,
+            ref AP.Complex[] y,
+            int iy1,
+            int iy2,
+            AP.Complex beta,
+            ref AP.Complex[] t)
+        {
+            int i = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( !transa )
+            {
+                
+                //
+                // y := alpha*A*x + beta*y
+                //
+                // or
+                //
+                // y := alpha*conj(A)*x + beta*y
+                //
+                if( i1>i2 | j1>j2 )
+                {
+                    return;
+                }
+                System.Diagnostics.Debug.Assert(j2-j1==ix2-ix1, "ComplexMatrixVectorMultiply: A and X dont match!");
+                System.Diagnostics.Debug.Assert(i2-i1==iy2-iy1, "ComplexMatrixVectorMultiply: A and Y dont match!");
+                
+                //
+                // beta*y
+                //
+                if( beta==0 )
+                {
+                    for(i=iy1; i<=iy2; i++)
+                    {
+                        y[i] = 0;
+                    }
+                }
+                else
+                {
+                    for(i_=iy1; i_<=iy2;i_++)
+                    {
+                        y[i_] = beta*y[i_];
+                    }
+                }
+                
+                //
+                // conj?
+                //
+                if( conja )
+                {
+                    for(i_=ix1; i_<=ix2;i_++)
+                    {
+                        t[i_] = AP.Math.Conj(x[i_]);
+                    }
+                    alpha = AP.Math.Conj(alpha);
+                    for(i_=iy1; i_<=iy2;i_++)
+                    {
+                        y[i_] = AP.Math.Conj(y[i_]);
+                    }
+                }
+                else
+                {
+                    for(i_=ix1; i_<=ix2;i_++)
+                    {
+                        t[i_] = x[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;
+                }
+                
+                //
+                // conj?
+                //
+                if( conja )
+                {
+                    for(i_=iy1; i_<=iy2;i_++)
+                    {
+                        y[i_] = AP.Math.Conj(y[i_]);
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // y := alpha*A'*x + beta*y;
+                //
+                // or
+                //
+                // y := alpha*conj(A')*x + beta*y;
+                //
+                if( i1>i2 | j1>j2 )
+                {
+                    return;
+                }
+                System.Diagnostics.Debug.Assert(i2-i1==ix2-ix1, "ComplexMatrixVectorMultiply: A and X dont match!");
+                System.Diagnostics.Debug.Assert(j2-j1==iy2-iy1, "ComplexMatrixVectorMultiply: A and Y dont match!");
+                
+                //
+                // beta*y
+                //
+                if( beta==0 )
+                {
+                    for(i=iy1; i<=iy2; i++)
+                    {
+                        y[i] = 0;
+                    }
+                }
+                else
+                {
+                    for(i_=iy1; i_<=iy2;i_++)
+                    {
+                        y[i_] = beta*y[i_];
+                    }
+                }
+                
+                //
+                // conj?
+                //
+                if( conja )
+                {
+                    for(i_=ix1; i_<=ix2;i_++)
+                    {
+                        t[i_] = AP.Math.Conj(x[i_]);
+                    }
+                    alpha = AP.Math.Conj(alpha);
+                    for(i_=iy1; i_<=iy2;i_++)
+                    {
+                        y[i_] = AP.Math.Conj(y[i_]);
+                    }
+                }
+                else
+                {
+                    for(i_=ix1; i_<=ix2;i_++)
+                    {
+                        t[i_] = x[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_];
+                    }
+                }
+                
+                //
+                // conj?
+                //
+                if( conja )
+                {
+                    for(i_=iy1; i_<=iy2;i_++)
+                    {
+                        y[i_] = AP.Math.Conj(y[i_]);
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cdet.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cdet.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cdet.cs	(revision 2645)
@@ -0,0 +1,128 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class cdet
+    {
+        /*************************************************************************
+        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       -   size of matrix A.
+
+        Result: matrix determinant.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static AP.Complex cmatrixludet(ref AP.Complex[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            AP.Complex result = 0;
+            int i = 0;
+            int s = 0;
+
+            result = 1;
+            s = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                result = result*a[i,i];
+                if( pivots[i]!=i )
+                {
+                    s = -s;
+                }
+            }
+            result = result*s;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Calculation of the determinant of a general matrix
+
+        Input parameters:
+            A       -   matrix, array[0..N-1, 0..N-1]
+            N       -   size of matrix A.
+
+        Result: determinant of matrix A.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static AP.Complex cmatrixdet(AP.Complex[,] a,
+            int n)
+        {
+            AP.Complex result = 0;
+            int[] pivots = new int[0];
+
+            a = (AP.Complex[,])a.Clone();
+
+            clu.cmatrixlu(ref a, n, n, ref pivots);
+            result = cmatrixludet(ref a, ref pivots, n);
+            return result;
+        }
+
+
+        public static AP.Complex complexdeterminantlu(ref AP.Complex[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            AP.Complex result = 0;
+            int i = 0;
+            int s = 0;
+
+            result = 1;
+            s = 1;
+            for(i=1; i<=n; i++)
+            {
+                result = result*a[i,i];
+                if( pivots[i]!=i )
+                {
+                    s = -s;
+                }
+            }
+            result = result*s;
+            return result;
+        }
+
+
+        public static AP.Complex complexdeterminant(AP.Complex[,] a,
+            int n)
+        {
+            AP.Complex result = 0;
+            int[] pivots = new int[0];
+
+            a = (AP.Complex[,])a.Clone();
+
+            clu.complexludecomposition(ref a, n, n, ref pivots);
+            result = complexdeterminantlu(ref a, ref pivots, n);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/chebyshev.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/chebyshev.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/chebyshev.cs	(revision 2645)
@@ -0,0 +1,238 @@
+/*************************************************************************
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class chebyshev
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static double chebyshevcalculate(int r,
+            int n,
+            double x)
+        {
+            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 )
+            {
+                result = a;
+                return result;
+            }
+            if( n==1 )
+            {
+                result = b;
+                return result;
+            }
+            
+            //
+            // General case: N>=2
+            //
+            for(i=2; i<=n; i++)
+            {
+                result = 2*x*b-a;
+                a = b;
+                b = result;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Summation of Chebyshev polynomials using Clenshaws recurrence formula.
+
+        This routine calculates
+            c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x)
+        or
+            c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x)
+        depending on the R.
+
+        Parameters:
+            r   -   polynomial kind, either 1 or 2.
+            n   -   degree, n>=0
+            x   -   argument
+
+        Result:
+            the value of the Chebyshev polynomial at x
+        *************************************************************************/
+        public static double chebyshevsum(ref double[] c,
+            int r,
+            int n,
+            double x)
+        {
+            double result = 0;
+            double b1 = 0;
+            double b2 = 0;
+            int i = 0;
+
+            b1 = 0;
+            b2 = 0;
+            for(i=n; i>=1; i--)
+            {
+                result = 2*x*b1-b2+c[i];
+                b2 = b1;
+                b1 = result;
+            }
+            if( r==1 )
+            {
+                result = -b2+x*b1+c[0];
+            }
+            else
+            {
+                result = -b2+2*x*b1+c[0];
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N
+
+        Input parameters:
+            N   -   polynomial degree, n>=0
+
+        Output parameters:
+            C   -   coefficients
+        *************************************************************************/
+        public static void chebyshevcoefficients(int n,
+            ref double[] c)
+        {
+            int i = 0;
+
+            c = new double[n+1];
+            for(i=0; i<=n; i++)
+            {
+                c[i] = 0;
+            }
+            if( n==0 | n==1 )
+            {
+                c[n] = 1;
+            }
+            else
+            {
+                c[n] = Math.Exp((n-1)*Math.Log(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)/(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
+        *************************************************************************/
+        public static void fromchebyshev(ref double[] a,
+            int n,
+            ref double[] b)
+        {
+            int i = 0;
+            int k = 0;
+            double e = 0;
+            double d = 0;
+
+            b = new double[n+1];
+            for(i=0; i<=n; i++)
+            {
+                b[i] = 0;
+            }
+            d = 0;
+            i = 0;
+            do
+            {
+                k = i;
+                do
+                {
+                    e = b[k];
+                    b[k] = 0;
+                    if( i<=1 & k==i )
+                    {
+                        b[k] = 1;
+                    }
+                    else
+                    {
+                        if( i!=0 )
+                        {
+                            b[k] = 2*d;
+                        }
+                        if( k>i+1 )
+                        {
+                            b[k] = b[k]-b[k-2];
+                        }
+                    }
+                    d = e;
+                    k = k+1;
+                }
+                while( k<=n );
+                d = b[i];
+                e = 0;
+                k = i;
+                while( k<=n )
+                {
+                    e = e+b[k]*a[k];
+                    k = k+2;
+                }
+                b[i] = e;
+                i = i+1;
+            }
+            while( i<=n );
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/chisquaredistr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/chisquaredistr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/chisquaredistr.cs	(revision 2645)
@@ -0,0 +1,150 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class chisquaredistr
+    {
+        /*************************************************************************
+        Chi-square distribution
+
+        Returns the area under the left hand tail (from 0 to x)
+        of the Chi square probability density function with
+        v degrees of freedom.
+
+
+                                          x
+                                           -
+                               1          | |  v/2-1  -t/2
+         P( x | v )   =   -----------     |   t      e     dt
+                           v/2  -       | |
+                          2    | (v/2)   -
+                                          0
+
+        where x is the Chi-square variable.
+
+        The incomplete gamma integral is used, according to the
+        formula
+
+        y = chdtr( v, x ) = igam( v/2.0, x/2.0 ).
+
+        The arguments must both be positive.
+
+        ACCURACY:
+
+        See incomplete gamma function
+
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double chisquaredistribution(double v,
+            double x)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert((double)(x)>=(double)(0) & (double)(v)>=(double)(1), "Domain error in ChiSquareDistribution");
+            result = igammaf.incompletegamma(v/2.0, x/2.0);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complemented Chi-square distribution
+
+        Returns the area under the right hand tail (from x to
+        infinity) of the Chi square probability density function
+        with v degrees of freedom:
+
+                                         inf.
+                                           -
+                               1          | |  v/2-1  -t/2
+         P( x | v )   =   -----------     |   t      e     dt
+                           v/2  -       | |
+                          2    | (v/2)   -
+                                          x
+
+        where x is the Chi-square variable.
+
+        The incomplete gamma integral is used, according to the
+        formula
+
+        y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ).
+
+        The arguments must both be positive.
+
+        ACCURACY:
+
+        See incomplete gamma function
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double chisquarecdistribution(double v,
+            double x)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert((double)(x)>=(double)(0) & (double)(v)>=(double)(1), "Domain error in ChiSquareDistributionC");
+            result = igammaf.incompletegammac(v/2.0, x/2.0);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse of complemented Chi-square distribution
+
+        Finds the Chi-square argument x such that the integral
+        from x to infinity of the Chi-square density is equal
+        to the given cumulative probability y.
+
+        This is accomplished using the inverse gamma integral
+        function and the relation
+
+           x/2 = igami( df/2, y );
+
+        ACCURACY:
+
+        See inverse incomplete gamma function
+
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invchisquaredistribution(double v,
+            double y)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert((double)(y)>=(double)(0) & (double)(y)<=(double)(1) & (double)(v)>=(double)(1), "Domain error in InvChiSquareDistribution");
+            result = 2*igammaf.invincompletegammac(0.5*v, y);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cholesky.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cholesky.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cholesky.cs	(revision 2645)
@@ -0,0 +1,321 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class cholesky
+    {
+        /*************************************************************************
+        Cholesky decomposition
+
+        The algorithm computes Cholesky decomposition of a symmetric
+        positive-definite matrix.
+
+        The result of an algorithm is a representation of matrix A as A = U'*U or
+        A = L*L'.
+
+        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. This means that the
+            factorization could not be carried out.
+
+          -- 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
+        *************************************************************************/
+        public static bool spdmatrixcholesky(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            double ajj = 0;
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            //     Test the input parameters.
+            //
+            System.Diagnostics.Debug.Assert(n>=0, "Error in SMatrixCholesky: incorrect function arguments");
+            
+            //
+            //     Quick return if possible
+            //
+            result = true;
+            if( n<=0 )
+            {
+                return result;
+            }
+            if( isupper )
+            {
+                
+                //
+                // Compute the Cholesky factorization A = U'*U.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    
+                    //
+                    // Compute U(J,J) and test for non-positive-definiteness.
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=j-1;i_++)
+                    {
+                        v += a[i_,j]*a[i_,j];
+                    }
+                    ajj = a[j,j]-v;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of row J.
+                    //
+                    if( j<n-1 )
+                    {
+                        for(i=0; i<=j-1; i++)
+                        {
+                            v = a[i,j];
+                            for(i_=j+1; i_<=n-1;i_++)
+                            {
+                                a[j,i_] = a[j,i_] - v*a[i,i_];
+                            }
+                        }
+                        v = 1/ajj;
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[j,i_] = v*a[j,i_];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute the Cholesky factorization A = L*L'.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    
+                    //
+                    // Compute L(J,J) and test for non-positive-definiteness.
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=j-1;i_++)
+                    {
+                        v += a[j,i_]*a[j,i_];
+                    }
+                    ajj = a[j,j]-v;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of column J.
+                    //
+                    if( j<n-1 )
+                    {
+                        for(i=j+1; i<=n-1; i++)
+                        {
+                            v = 0.0;
+                            for(i_=0; i_<=j-1;i_++)
+                            {
+                                v += a[i,i_]*a[j,i_];
+                            }
+                            a[i,j] = a[i,j]-v;
+                        }
+                        v = 1/ajj;
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[i_,j] = v*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool choleskydecomposition(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            double ajj = 0;
+            double v = 0;
+            int jm1 = 0;
+            int jp1 = 0;
+            int i_ = 0;
+
+            
+            //
+            //     Test the input parameters.
+            //
+            System.Diagnostics.Debug.Assert(n>=0, "Error in CholeskyDecomposition: incorrect function arguments");
+            
+            //
+            //     Quick return if possible
+            //
+            result = true;
+            if( n==0 )
+            {
+                return result;
+            }
+            if( isupper )
+            {
+                
+                //
+                // Compute the Cholesky factorization A = U'*U.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Compute U(J,J) and test for non-positive-definiteness.
+                    //
+                    jm1 = j-1;
+                    v = 0.0;
+                    for(i_=1; i_<=jm1;i_++)
+                    {
+                        v += a[i_,j]*a[i_,j];
+                    }
+                    ajj = a[j,j]-v;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of row J.
+                    //
+                    if( j<n )
+                    {
+                        for(i=j+1; i<=n; i++)
+                        {
+                            jm1 = j-1;
+                            v = 0.0;
+                            for(i_=1; i_<=jm1;i_++)
+                            {
+                                v += a[i_,i]*a[i_,j];
+                            }
+                            a[j,i] = a[j,i]-v;
+                        }
+                        v = 1/ajj;
+                        jp1 = j+1;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            a[j,i_] = v*a[j,i_];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute the Cholesky factorization A = L*L'.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Compute L(J,J) and test for non-positive-definiteness.
+                    //
+                    jm1 = j-1;
+                    v = 0.0;
+                    for(i_=1; i_<=jm1;i_++)
+                    {
+                        v += a[j,i_]*a[j,i_];
+                    }
+                    ajj = a[j,j]-v;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of column J.
+                    //
+                    if( j<n )
+                    {
+                        for(i=j+1; i<=n; i++)
+                        {
+                            jm1 = j-1;
+                            v = 0.0;
+                            for(i_=1; i_<=jm1;i_++)
+                            {
+                                v += a[i,i_]*a[j,i_];
+                            }
+                            a[i,j] = a[i,j]-v;
+                        }
+                        v = 1/ajj;
+                        jp1 = j+1;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            a[i_,j] = v*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cinverse.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cinverse.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cinverse.cs	(revision 2645)
@@ -0,0 +1,284 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class cinverse
+    {
+        /*************************************************************************
+        Inversion of a complex matrix given by its LU decomposition.
+
+        Input parameters:
+            A       -   LU decomposition of the matrix (output of CMatrixLU subroutine).
+            Pivots  -   table of permutations which were made during the LU decomposition
+                        (the output of CMatrixLU subroutine).
+            N       -   size of matrix A.
+
+        Output parameters:
+            A       -   inverse of matrix A.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular.
+
+          -- 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
+        *************************************************************************/
+        public static bool cmatrixluinverse(ref AP.Complex[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            bool result = new bool();
+            AP.Complex[] work = new AP.Complex[0];
+            int i = 0;
+            int iws = 0;
+            int j = 0;
+            int jb = 0;
+            int jj = 0;
+            int jp = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            work = new AP.Complex[n-1+1];
+            
+            //
+            // Form inv(U)
+            //
+            if( !ctrinverse.cmatrixtrinverse(ref a, n, true, false) )
+            {
+                result = false;
+                return result;
+            }
+            
+            //
+            // Solve the equation inv(A)*L = inv(U) for inv(A).
+            //
+            for(j=n-1; j>=0; j--)
+            {
+                
+                //
+                // Copy current column of L to WORK and replace with zeros.
+                //
+                for(i=j+1; i<=n-1; i++)
+                {
+                    work[i] = a[i,j];
+                    a[i,j] = 0;
+                }
+                
+                //
+                // Compute current column of inv(A).
+                //
+                if( j<n-1 )
+                {
+                    for(i=0; i<=n-1; i++)
+                    {
+                        v = 0.0;
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            v += a[i,i_]*work[i_];
+                        }
+                        a[i,j] = a[i,j]-v;
+                    }
+                }
+            }
+            
+            //
+            // Apply column interchanges.
+            //
+            for(j=n-2; j>=0; j--)
+            {
+                jp = pivots[j];
+                if( jp!=j )
+                {
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        work[i_] = a[i_,j];
+                    }
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        a[i_,j] = a[i_,jp];
+                    }
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        a[i_,jp] = work[i_];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inversion of a general complex matrix.
+
+        Input parameters:
+            A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
+            N   -   size of matrix A.
+
+        Output parameters:
+            A   -   inverse of matrix A.
+                    Array whose indexes range within [0..N-1, 0..N-1].
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool cmatrixinverse(ref AP.Complex[,] a,
+            int n)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            clu.cmatrixlu(ref a, n, n, ref pivots);
+            result = cmatrixluinverse(ref a, ref pivots, n);
+            return result;
+        }
+
+
+        public static bool complexinverselu(ref AP.Complex[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            bool result = new bool();
+            AP.Complex[] work = new AP.Complex[0];
+            int i = 0;
+            int iws = 0;
+            int j = 0;
+            int jb = 0;
+            int jj = 0;
+            int jp = 0;
+            int jp1 = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            work = new AP.Complex[n+1];
+            
+            //
+            // Form inv(U)
+            //
+            if( !ctrinverse.complexinvtriangular(ref a, n, true, false) )
+            {
+                result = false;
+                return result;
+            }
+            
+            //
+            // Solve the equation inv(A)*L = inv(U) for inv(A).
+            //
+            for(j=n; j>=1; j--)
+            {
+                
+                //
+                // Copy current column of L to WORK and replace with zeros.
+                //
+                for(i=j+1; i<=n; i++)
+                {
+                    work[i] = a[i,j];
+                    a[i,j] = 0;
+                }
+                
+                //
+                // Compute current column of inv(A).
+                //
+                if( j<n )
+                {
+                    jp1 = j+1;
+                    for(i=1; i<=n; i++)
+                    {
+                        v = 0.0;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            v += a[i,i_]*work[i_];
+                        }
+                        a[i,j] = a[i,j]-v;
+                    }
+                }
+            }
+            
+            //
+            // Apply column interchanges.
+            //
+            for(j=n-1; j>=1; j--)
+            {
+                jp = pivots[j];
+                if( jp!=j )
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        work[i_] = a[i_,j];
+                    }
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        a[i_,j] = a[i_,jp];
+                    }
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        a[i_,jp] = work[i_];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool complexinverse(ref AP.Complex[,] a,
+            int n)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            clu.complexludecomposition(ref a, n, n, ref pivots);
+            result = complexinverselu(ref a, ref pivots, n);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/clu.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/clu.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/clu.cs	(revision 2645)
@@ -0,0 +1,321 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee. All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class clu
+    {
+        /*************************************************************************
+        LU decomposition of a complex general matrix of size MxN
+
+        The subroutine calculates the LU decomposition of a rectangular general
+        matrix with partial pivoting (with row permutations).
+
+        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 U in compact form (see below).
+                    Array whose indexes range within [0..M-1, 0..N-1].
+            Pivots - permutation matrix in compact form (see below).
+                    Array whose index ranges within [0..Min(M-1,N-1)].
+
+        Matrix A is represented as A = P * L * U, where P is a permutation matrix,
+        matrix L - lower triangular (or lower trapezoid, if M>N) matrix,
+        U - upper triangular (or upper trapezoid, if M<N) matrix.
+
+        Let M be equal to 4 and N be equal to 3:
+
+                           (  1          )    ( U11 U12 U13  )
+        A = P1 * P2 * P3 * ( L21  1      )  * (     U22 U23  )
+                           ( L31 L32  1  )    (         U33  )
+                           ( L41 L42 L43 )
+
+        Matrix L has size MxMin(M,N), matrix U has size Min(M,N)xN, matrix P(i) is
+        a permutation of the identity matrix of size MxM with numbers I and Pivots[I].
+
+        The algorithm returns array Pivots and the following matrix which replaces
+        matrix A and contains matrices L and U in compact form (the example applies
+        to M=4, N=3).
+
+         ( U11 U12 U13 )
+         ( L21 U22 U23 )
+         ( L31 L32 U33 )
+         ( L41 L42 L43 )
+
+        As we can see, the unit diagonal isn't stored.
+
+          -- LAPACK routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             June 30, 1992
+        *************************************************************************/
+        public static void cmatrixlu(ref AP.Complex[,] a,
+            int m,
+            int n,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int j = 0;
+            int jp = 0;
+            AP.Complex[] t1 = new AP.Complex[0];
+            AP.Complex s = 0;
+            int i_ = 0;
+
+            pivots = new int[Math.Min(m-1, n-1)+1];
+            t1 = new AP.Complex[Math.Max(m-1, n-1)+1];
+            System.Diagnostics.Debug.Assert(m>=0 & n>=0, "Error in LUDecomposition: incorrect function arguments");
+            
+            //
+            // Quick return if possible
+            //
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            for(j=0; j<=Math.Min(m-1, n-1); j++)
+            {
+                
+                //
+                // Find pivot and test for singularity.
+                //
+                jp = j;
+                for(i=j+1; i<=m-1; i++)
+                {
+                    if( (double)(AP.Math.AbsComplex(a[i,j]))>(double)(AP.Math.AbsComplex(a[jp,j])) )
+                    {
+                        jp = i;
+                    }
+                }
+                pivots[j] = jp;
+                if( a[jp,j]!=0 )
+                {
+                    
+                    //
+                    //Apply the interchange to rows
+                    //
+                    if( jp!=j )
+                    {
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            t1[i_] = a[j,i_];
+                        }
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            a[j,i_] = a[jp,i_];
+                        }
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            a[jp,i_] = t1[i_];
+                        }
+                    }
+                    
+                    //
+                    //Compute elements J+1:M of J-th column.
+                    //
+                    if( j<m )
+                    {
+                        jp = j+1;
+                        s = 1/a[j,j];
+                        for(i_=jp; i_<=m-1;i_++)
+                        {
+                            a[i_,j] = s*a[i_,j];
+                        }
+                    }
+                }
+                if( j<Math.Min(m, n)-1 )
+                {
+                    
+                    //
+                    //Update trailing submatrix.
+                    //
+                    jp = j+1;
+                    for(i=j+1; i<=m-1; i++)
+                    {
+                        s = a[i,j];
+                        for(i_=jp; i_<=n-1;i_++)
+                        {
+                            a[i,i_] = a[i,i_] - s*a[j,i_];
+                        }
+                    }
+                }
+            }
+        }
+
+
+        public static void complexludecomposition(ref AP.Complex[,] a,
+            int m,
+            int n,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int j = 0;
+            int jp = 0;
+            AP.Complex[] t1 = new AP.Complex[0];
+            AP.Complex s = 0;
+            int i_ = 0;
+
+            pivots = new int[Math.Min(m, n)+1];
+            t1 = new AP.Complex[Math.Max(m, n)+1];
+            System.Diagnostics.Debug.Assert(m>=0 & n>=0, "Error in ComplexLUDecomposition: incorrect function arguments");
+            
+            //
+            // Quick return if possible
+            //
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            for(j=1; j<=Math.Min(m, n); j++)
+            {
+                
+                //
+                // Find pivot and test for singularity.
+                //
+                jp = j;
+                for(i=j+1; i<=m; i++)
+                {
+                    if( (double)(AP.Math.AbsComplex(a[i,j]))>(double)(AP.Math.AbsComplex(a[jp,j])) )
+                    {
+                        jp = i;
+                    }
+                }
+                pivots[j] = jp;
+                if( a[jp,j]!=0 )
+                {
+                    
+                    //
+                    //Apply the interchange to rows
+                    //
+                    if( jp!=j )
+                    {
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            t1[i_] = a[j,i_];
+                        }
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            a[j,i_] = a[jp,i_];
+                        }
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            a[jp,i_] = t1[i_];
+                        }
+                    }
+                    
+                    //
+                    //Compute elements J+1:M of J-th column.
+                    //
+                    if( j<m )
+                    {
+                        jp = j+1;
+                        s = 1/a[j,j];
+                        for(i_=jp; i_<=m;i_++)
+                        {
+                            a[i_,j] = s*a[i_,j];
+                        }
+                    }
+                }
+                if( j<Math.Min(m, n) )
+                {
+                    
+                    //
+                    //Update trailing submatrix.
+                    //
+                    jp = j+1;
+                    for(i=j+1; i<=m; i++)
+                    {
+                        s = a[i,j];
+                        for(i_=jp; i_<=n;i_++)
+                        {
+                            a[i,i_] = a[i,i_] - s*a[j,i_];
+                        }
+                    }
+                }
+            }
+        }
+
+
+        public static void complexludecompositionunpacked(AP.Complex[,] a,
+            int m,
+            int n,
+            ref AP.Complex[,] l,
+            ref AP.Complex[,] u,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int j = 0;
+            int minmn = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            minmn = Math.Min(m, n);
+            l = new AP.Complex[m+1, minmn+1];
+            u = new AP.Complex[minmn+1, n+1];
+            complexludecomposition(ref a, m, n, ref pivots);
+            for(i=1; i<=m; i++)
+            {
+                for(j=1; j<=minmn; j++)
+                {
+                    if( j>i )
+                    {
+                        l[i,j] = 0;
+                    }
+                    if( j==i )
+                    {
+                        l[i,j] = 1;
+                    }
+                    if( j<i )
+                    {
+                        l[i,j] = a[i,j];
+                    }
+                }
+            }
+            for(i=1; i<=minmn; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( j<i )
+                    {
+                        u[i,j] = 0;
+                    }
+                    if( j>=i )
+                    {
+                        u[i,j] = a[i,j];
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/conv.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/conv.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/conv.cs	(revision 2645)
@@ -0,0 +1,1695 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class conv
+    {
+        /*************************************************************************
+        1-dimensional complex convolution.
+
+        For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
+        choose between three implementations: straightforward O(M*N)  formula  for
+        very small N (or M), overlap-add algorithm for  cases  where  max(M,N)  is
+        significantly larger than min(M,N), but O(M*N) algorithm is too slow,  and
+        general FFT-based formula for cases where two previois algorithms are  too
+        slow.
+
+        Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - complex function to be transformed
+            M   -   problem size
+            B   -   array[0..N-1] - complex function to be transformed
+            N   -   problem size
+
+        OUTPUT PARAMETERS
+            R   -   convolution: A*B. array[0..N+M-2].
+
+        NOTE:
+            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convc1d(ref AP.Complex[] a,
+            int m,
+            ref AP.Complex[] b,
+            int n,
+            ref AP.Complex[] r)
+        {
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1D: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer that B.
+            //
+            if( m<n )
+            {
+                convc1d(ref b, n, ref a, m, ref r);
+                return;
+            }
+            convc1dx(ref a, m, ref b, n, false, -1, 0, ref r);
+        }
+
+
+        /*************************************************************************
+        1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
+
+        Algorithm has M*log(M)) complexity for any M (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
+            M   -   convolved signal length
+            B   -   array[0..N-1] - response
+            N   -   response length, N<=M
+
+        OUTPUT PARAMETERS
+            R   -   deconvolved signal. array[0..M-N].
+
+        NOTE:
+            deconvolution is unstable process and may result in division  by  zero
+        (if your response function is degenerate, i.e. has zero Fourier coefficient).
+
+        NOTE:
+            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convc1dinv(ref AP.Complex[] a,
+            int m,
+            ref AP.Complex[] b,
+            int n,
+            ref AP.Complex[] r)
+        {
+            int i = 0;
+            int p = 0;
+            double[] buf = new double[0];
+            double[] buf2 = new double[0];
+            ftbase.ftplan plan = new ftbase.ftplan();
+            AP.Complex c1 = 0;
+            AP.Complex c2 = 0;
+            AP.Complex c3 = 0;
+            double t = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0 & n<=m, "ConvC1DInv: incorrect N or M!");
+            p = ftbase.ftbasefindsmooth(m);
+            ftbase.ftbasegeneratecomplexfftplan(p, ref plan);
+            buf = new double[2*p];
+            for(i=0; i<=m-1; i++)
+            {
+                buf[2*i+0] = a[i].x;
+                buf[2*i+1] = a[i].y;
+            }
+            for(i=m; i<=p-1; i++)
+            {
+                buf[2*i+0] = 0;
+                buf[2*i+1] = 0;
+            }
+            buf2 = new double[2*p];
+            for(i=0; i<=n-1; i++)
+            {
+                buf2[2*i+0] = b[i].x;
+                buf2[2*i+1] = b[i].y;
+            }
+            for(i=n; i<=p-1; i++)
+            {
+                buf2[2*i+0] = 0;
+                buf2[2*i+1] = 0;
+            }
+            ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
+            ftbase.ftbaseexecuteplan(ref buf2, 0, p, ref plan);
+            for(i=0; i<=p-1; i++)
+            {
+                c1.x = buf[2*i+0];
+                c1.y = buf[2*i+1];
+                c2.x = buf2[2*i+0];
+                c2.y = buf2[2*i+1];
+                c3 = c1/c2;
+                buf[2*i+0] = c3.x;
+                buf[2*i+1] = -c3.y;
+            }
+            ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
+            t = (double)(1)/(double)(p);
+            r = new AP.Complex[m-n+1];
+            for(i=0; i<=m-n; i++)
+            {
+                r[i].x = +(t*buf[2*i+0]);
+                r[i].y = -(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 A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convc1dcircular(ref AP.Complex[] s,
+            int m,
+            ref AP.Complex[] r,
+            int n,
+            ref AP.Complex[] c)
+        {
+            AP.Complex[] buf = new AP.Complex[0];
+            int i1 = 0;
+            int i2 = 0;
+            int j2 = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircular: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer (at least - not shorter) that B.
+            //
+            if( m<n )
+            {
+                buf = new AP.Complex[m];
+                for(i1=0; i1<=m-1; i1++)
+                {
+                    buf[i1] = 0;
+                }
+                i1 = 0;
+                while( i1<n )
+                {
+                    i2 = Math.Min(i1+m-1, n-1);
+                    j2 = i2-i1;
+                    i1_ = (i1) - (0);
+                    for(i_=0; i_<=j2;i_++)
+                    {
+                        buf[i_] = buf[i_] + r[i_+i1_];
+                    }
+                    i1 = i1+m;
+                }
+                convc1dcircular(ref s, m, ref buf, m, ref c);
+                return;
+            }
+            convc1dx(ref s, m, ref r, n, true, -1, 0, ref c);
+        }
+
+
+        /*************************************************************************
+        1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
+
+        Algorithm has M*log(M)) complexity for any M (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - convolved periodic signal, A = conv(R, B)
+            M   -   convolved signal length
+            B   -   array[0..N-1] - non-periodic response
+            N   -   response length
+
+        OUTPUT PARAMETERS
+            R   -   deconvolved signal. array[0..M-1].
+
+        NOTE:
+            deconvolution is unstable process and may result in division  by  zero
+        (if your response function is degenerate, i.e. has zero Fourier coefficient).
+
+        NOTE:
+            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convc1dcircularinv(ref AP.Complex[] a,
+            int m,
+            ref AP.Complex[] b,
+            int n,
+            ref AP.Complex[] r)
+        {
+            int i = 0;
+            int p = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int j2 = 0;
+            double[] buf = new double[0];
+            double[] buf2 = new double[0];
+            AP.Complex[] cbuf = new AP.Complex[0];
+            ftbase.ftplan plan = new ftbase.ftplan();
+            AP.Complex c1 = 0;
+            AP.Complex c2 = 0;
+            AP.Complex c3 = 0;
+            double t = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircularInv: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer (at least - not shorter) that B.
+            //
+            if( m<n )
+            {
+                cbuf = new AP.Complex[m];
+                for(i=0; i<=m-1; i++)
+                {
+                    cbuf[i] = 0;
+                }
+                i1 = 0;
+                while( i1<n )
+                {
+                    i2 = Math.Min(i1+m-1, n-1);
+                    j2 = i2-i1;
+                    i1_ = (i1) - (0);
+                    for(i_=0; i_<=j2;i_++)
+                    {
+                        cbuf[i_] = cbuf[i_] + b[i_+i1_];
+                    }
+                    i1 = i1+m;
+                }
+                convc1dcircularinv(ref a, m, ref cbuf, m, ref r);
+                return;
+            }
+            
+            //
+            // Task is normalized
+            //
+            ftbase.ftbasegeneratecomplexfftplan(m, ref plan);
+            buf = new double[2*m];
+            for(i=0; i<=m-1; i++)
+            {
+                buf[2*i+0] = a[i].x;
+                buf[2*i+1] = a[i].y;
+            }
+            buf2 = new double[2*m];
+            for(i=0; i<=n-1; i++)
+            {
+                buf2[2*i+0] = b[i].x;
+                buf2[2*i+1] = b[i].y;
+            }
+            for(i=n; i<=m-1; i++)
+            {
+                buf2[2*i+0] = 0;
+                buf2[2*i+1] = 0;
+            }
+            ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
+            ftbase.ftbaseexecuteplan(ref buf2, 0, m, ref plan);
+            for(i=0; i<=m-1; i++)
+            {
+                c1.x = buf[2*i+0];
+                c1.y = buf[2*i+1];
+                c2.x = buf2[2*i+0];
+                c2.y = buf2[2*i+1];
+                c3 = c1/c2;
+                buf[2*i+0] = c3.x;
+                buf[2*i+1] = -c3.y;
+            }
+            ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
+            t = (double)(1)/(double)(m);
+            r = new AP.Complex[m];
+            for(i=0; i<=m-1; i++)
+            {
+                r[i].x = +(t*buf[2*i+0]);
+                r[i].y = -(t*buf[2*i+1]);
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional real convolution.
+
+        Analogous to ConvC1D(), see ConvC1D() comments for more details.
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - real function to be transformed
+            M   -   problem size
+            B   -   array[0..N-1] - real function to be transformed
+            N   -   problem size
+
+        OUTPUT PARAMETERS
+            R   -   convolution: A*B. array[0..N+M-2].
+
+        NOTE:
+            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convr1d(ref double[] a,
+            int m,
+            ref double[] b,
+            int n,
+            ref double[] r)
+        {
+            int i = 0;
+            int j = 0;
+            int p = 0;
+            int q = 0;
+            AP.Complex[] abuf = new AP.Complex[0];
+            AP.Complex[] bbuf = new AP.Complex[0];
+            AP.Complex v = 0;
+            double flop1 = 0;
+            double flop2 = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvR1D: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer that B.
+            //
+            if( m<n )
+            {
+                convr1d(ref b, n, ref a, m, ref r);
+                return;
+            }
+            convr1dx(ref a, m, ref b, n, false, -1, 0, ref r);
+        }
+
+
+        /*************************************************************************
+        1-dimensional real deconvolution (inverse of ConvC1D()).
+
+        Algorithm has M*log(M)) complexity for any M (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
+            M   -   convolved signal length
+            B   -   array[0..N-1] - response
+            N   -   response length, N<=M
+
+        OUTPUT PARAMETERS
+            R   -   deconvolved signal. array[0..M-N].
+
+        NOTE:
+            deconvolution is unstable process and may result in division  by  zero
+        (if your response function is degenerate, i.e. has zero Fourier coefficient).
+
+        NOTE:
+            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convr1dinv(ref double[] a,
+            int m,
+            ref double[] b,
+            int n,
+            ref double[] r)
+        {
+            int i = 0;
+            int p = 0;
+            double[] buf = new double[0];
+            double[] buf2 = new double[0];
+            double[] buf3 = new double[0];
+            ftbase.ftplan plan = new ftbase.ftplan();
+            AP.Complex c1 = 0;
+            AP.Complex c2 = 0;
+            AP.Complex c3 = 0;
+            double t = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0 & n<=m, "ConvR1DInv: incorrect N or M!");
+            p = ftbase.ftbasefindsmootheven(m);
+            buf = new double[p];
+            for(i_=0; i_<=m-1;i_++)
+            {
+                buf[i_] = a[i_];
+            }
+            for(i=m; i<=p-1; i++)
+            {
+                buf[i] = 0;
+            }
+            buf2 = new double[p];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                buf2[i_] = b[i_];
+            }
+            for(i=n; i<=p-1; i++)
+            {
+                buf2[i] = 0;
+            }
+            buf3 = new double[p];
+            ftbase.ftbasegeneratecomplexfftplan(p/2, ref plan);
+            fft.fftr1dinternaleven(ref buf, p, ref buf3, ref plan);
+            fft.fftr1dinternaleven(ref buf2, p, ref buf3, ref plan);
+            buf[0] = buf[0]/buf2[0];
+            buf[1] = buf[1]/buf2[1];
+            for(i=1; i<=p/2-1; i++)
+            {
+                c1.x = buf[2*i+0];
+                c1.y = buf[2*i+1];
+                c2.x = buf2[2*i+0];
+                c2.y = buf2[2*i+1];
+                c3 = c1/c2;
+                buf[2*i+0] = c3.x;
+                buf[2*i+1] = c3.y;
+            }
+            fft.fftr1dinvinternaleven(ref buf, p, ref buf3, ref plan);
+            r = new double[m-n+1];
+            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 A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convr1dcircular(ref double[] s,
+            int m,
+            ref double[] r,
+            int n,
+            ref double[] c)
+        {
+            double[] buf = new double[0];
+            int i1 = 0;
+            int i2 = 0;
+            int j2 = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircular: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer (at least - not shorter) that B.
+            //
+            if( m<n )
+            {
+                buf = new double[m];
+                for(i1=0; i1<=m-1; i1++)
+                {
+                    buf[i1] = 0;
+                }
+                i1 = 0;
+                while( i1<n )
+                {
+                    i2 = Math.Min(i1+m-1, n-1);
+                    j2 = i2-i1;
+                    i1_ = (i1) - (0);
+                    for(i_=0; i_<=j2;i_++)
+                    {
+                        buf[i_] = buf[i_] + r[i_+i1_];
+                    }
+                    i1 = i1+m;
+                }
+                convr1dcircular(ref s, m, ref buf, m, ref c);
+                return;
+            }
+            
+            //
+            // reduce to usual convolution
+            //
+            convr1dx(ref s, m, ref r, n, true, -1, 0, ref c);
+        }
+
+
+        /*************************************************************************
+        1-dimensional complex deconvolution (inverse of ConvC1D()).
+
+        Algorithm has M*log(M)) complexity for any M (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - convolved signal, A = conv(R, B)
+            M   -   convolved signal length
+            B   -   array[0..N-1] - response
+            N   -   response length
+
+        OUTPUT PARAMETERS
+            R   -   deconvolved signal. array[0..M-N].
+
+        NOTE:
+            deconvolution is unstable process and may result in division  by  zero
+        (if your response function is degenerate, i.e. has zero Fourier coefficient).
+
+        NOTE:
+            It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
+        functions have non-zero values at negative T's, you  can  still  use  this
+        subroutine - just shift its result correspondingly.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convr1dcircularinv(ref double[] a,
+            int m,
+            ref double[] b,
+            int n,
+            ref double[] r)
+        {
+            int i = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int j2 = 0;
+            double[] buf = new double[0];
+            double[] buf2 = new double[0];
+            double[] buf3 = new double[0];
+            AP.Complex[] cbuf = new AP.Complex[0];
+            AP.Complex[] cbuf2 = new AP.Complex[0];
+            ftbase.ftplan plan = new ftbase.ftplan();
+            AP.Complex c1 = 0;
+            AP.Complex c2 = 0;
+            AP.Complex c3 = 0;
+            double t = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvR1DCircularInv: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer (at least - not shorter) that B.
+            //
+            if( m<n )
+            {
+                buf = new double[m];
+                for(i=0; i<=m-1; i++)
+                {
+                    buf[i] = 0;
+                }
+                i1 = 0;
+                while( i1<n )
+                {
+                    i2 = Math.Min(i1+m-1, n-1);
+                    j2 = i2-i1;
+                    i1_ = (i1) - (0);
+                    for(i_=0; i_<=j2;i_++)
+                    {
+                        buf[i_] = buf[i_] + b[i_+i1_];
+                    }
+                    i1 = i1+m;
+                }
+                convr1dcircularinv(ref a, m, ref buf, m, ref r);
+                return;
+            }
+            
+            //
+            // Task is normalized
+            //
+            if( m%2==0 )
+            {
+                
+                //
+                // size is even, use fast even-size FFT
+                //
+                buf = new double[m];
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    buf[i_] = a[i_];
+                }
+                buf2 = new double[m];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    buf2[i_] = b[i_];
+                }
+                for(i=n; i<=m-1; i++)
+                {
+                    buf2[i] = 0;
+                }
+                buf3 = new double[m];
+                ftbase.ftbasegeneratecomplexfftplan(m/2, ref plan);
+                fft.fftr1dinternaleven(ref buf, m, ref buf3, ref plan);
+                fft.fftr1dinternaleven(ref buf2, m, ref buf3, ref plan);
+                buf[0] = buf[0]/buf2[0];
+                buf[1] = buf[1]/buf2[1];
+                for(i=1; i<=m/2-1; i++)
+                {
+                    c1.x = buf[2*i+0];
+                    c1.y = buf[2*i+1];
+                    c2.x = buf2[2*i+0];
+                    c2.y = buf2[2*i+1];
+                    c3 = c1/c2;
+                    buf[2*i+0] = c3.x;
+                    buf[2*i+1] = c3.y;
+                }
+                fft.fftr1dinvinternaleven(ref buf, m, ref buf3, ref plan);
+                r = new double[m];
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    r[i_] = buf[i_];
+                }
+            }
+            else
+            {
+                
+                //
+                // odd-size, use general real FFT
+                //
+                fft.fftr1d(ref a, m, ref cbuf);
+                buf2 = new double[m];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    buf2[i_] = b[i_];
+                }
+                for(i=n; i<=m-1; i++)
+                {
+                    buf2[i] = 0;
+                }
+                fft.fftr1d(ref buf2, m, ref cbuf2);
+                for(i=0; i<=(int)Math.Floor((double)(m)/(double)(2)); i++)
+                {
+                    cbuf[i] = cbuf[i]/cbuf2[i];
+                }
+                fft.fftr1dinv(ref cbuf, m, ref r);
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional complex convolution.
+
+        Extended subroutine which allows to choose convolution algorithm.
+        Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular().
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - complex function to be transformed
+            M   -   problem size
+            B   -   array[0..N-1] - complex function to be transformed
+            N   -   problem size, N<=M
+            Alg -   algorithm type:
+                    *-2     auto-select Q for overlap-add
+                    *-1     auto-select algorithm and parameters
+                    * 0     straightforward formula for small N's
+                    * 1     general FFT-based code
+                    * 2     overlap-add with length Q
+            Q   -   length for overlap-add
+
+        OUTPUT PARAMETERS
+            R   -   convolution: A*B. array[0..N+M-1].
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convc1dx(ref AP.Complex[] a,
+            int m,
+            ref AP.Complex[] b,
+            int n,
+            bool circular,
+            int alg,
+            int q,
+            ref AP.Complex[] r)
+        {
+            int i = 0;
+            int j = 0;
+            int p = 0;
+            int ptotal = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int j1 = 0;
+            int j2 = 0;
+            AP.Complex[] bbuf = new AP.Complex[0];
+            AP.Complex v = 0;
+            double ax = 0;
+            double ay = 0;
+            double bx = 0;
+            double by = 0;
+            double t = 0;
+            double tx = 0;
+            double ty = 0;
+            double flopcand = 0;
+            double flopbest = 0;
+            int algbest = 0;
+            ftbase.ftplan plan = new ftbase.ftplan();
+            double[] buf = new double[0];
+            double[] buf2 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DX: incorrect N or M!");
+            System.Diagnostics.Debug.Assert(n<=m, "ConvC1DX: N<M assumption is false!");
+            
+            //
+            // Auto-select
+            //
+            if( alg==-1 | alg==-2 )
+            {
+                
+                //
+                // Initial candidate: straightforward implementation.
+                //
+                // If we want to use auto-fitted overlap-add,
+                // flop count is initialized by large real number - to force
+                // another algorithm selection
+                //
+                algbest = 0;
+                if( alg==-1 )
+                {
+                    flopbest = 2*m*n;
+                }
+                else
+                {
+                    flopbest = AP.Math.MaxRealNumber;
+                }
+                
+                //
+                // Another candidate - generic FFT code
+                //
+                if( alg==-1 )
+                {
+                    if( circular & ftbase.ftbaseissmooth(m) )
+                    {
+                        
+                        //
+                        // special code for circular convolution of a sequence with a smooth length
+                        //
+                        flopcand = 3*ftbase.ftbasegetflopestimate(m)+6*m;
+                        if( (double)(flopcand)<(double)(flopbest) )
+                        {
+                            algbest = 1;
+                            flopbest = flopcand;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // general cyclic/non-cyclic convolution
+                        //
+                        p = ftbase.ftbasefindsmooth(m+n-1);
+                        flopcand = 3*ftbase.ftbasegetflopestimate(p)+6*p;
+                        if( (double)(flopcand)<(double)(flopbest) )
+                        {
+                            algbest = 1;
+                            flopbest = flopcand;
+                        }
+                    }
+                }
+                
+                //
+                // Another candidate - overlap-add
+                //
+                q = 1;
+                ptotal = 1;
+                while( ptotal<n )
+                {
+                    ptotal = ptotal*2;
+                }
+                while( ptotal<=m+n-1 )
+                {
+                    p = ptotal-n+1;
+                    flopcand = (int)Math.Ceiling((double)(m)/(double)(p))*(2*ftbase.ftbasegetflopestimate(ptotal)+8*ptotal);
+                    if( (double)(flopcand)<(double)(flopbest) )
+                    {
+                        flopbest = flopcand;
+                        algbest = 2;
+                        q = p;
+                    }
+                    ptotal = ptotal*2;
+                }
+                alg = algbest;
+                convc1dx(ref a, m, ref b, n, circular, alg, q, ref r);
+                return;
+            }
+            
+            //
+            // straightforward formula for
+            // circular and non-circular convolutions.
+            //
+            // Very simple code, no further comments needed.
+            //
+            if( alg==0 )
+            {
+                
+                //
+                // Special case: N=1
+                //
+                if( n==1 )
+                {
+                    r = new AP.Complex[m];
+                    v = b[0];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        r[i_] = v*a[i_];
+                    }
+                    return;
+                }
+                
+                //
+                // use straightforward formula
+                //
+                if( circular )
+                {
+                    
+                    //
+                    // circular convolution
+                    //
+                    r = new AP.Complex[m];
+                    v = b[0];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        r[i_] = v*a[i_];
+                    }
+                    for(i=1; i<=n-1; i++)
+                    {
+                        v = b[i];
+                        i1 = 0;
+                        i2 = i-1;
+                        j1 = m-i;
+                        j2 = m-1;
+                        i1_ = (j1) - (i1);
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            r[i_] = r[i_] + v*a[i_+i1_];
+                        }
+                        i1 = i;
+                        i2 = m-1;
+                        j1 = 0;
+                        j2 = m-i-1;
+                        i1_ = (j1) - (i1);
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            r[i_] = r[i_] + v*a[i_+i1_];
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // non-circular convolution
+                    //
+                    r = new AP.Complex[m+n-1];
+                    for(i=0; i<=m+n-2; i++)
+                    {
+                        r[i] = 0;
+                    }
+                    for(i=0; i<=n-1; i++)
+                    {
+                        v = b[i];
+                        i1_ = (0) - (i);
+                        for(i_=i; i_<=i+m-1;i_++)
+                        {
+                            r[i_] = r[i_] + v*a[i_+i1_];
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // general FFT-based code for
+            // circular and non-circular convolutions.
+            //
+            // First, if convolution is circular, we test whether M is smooth or not.
+            // If it is smooth, we just use M-length FFT to calculate convolution.
+            // If it is not, we calculate non-circular convolution and wrap it arount.
+            //
+            // IF convolution is non-circular, we use zero-padding + FFT.
+            //
+            if( alg==1 )
+            {
+                if( circular & ftbase.ftbaseissmooth(m) )
+                {
+                    
+                    //
+                    // special code for circular convolution with smooth M
+                    //
+                    ftbase.ftbasegeneratecomplexfftplan(m, ref plan);
+                    buf = new double[2*m];
+                    for(i=0; i<=m-1; i++)
+                    {
+                        buf[2*i+0] = a[i].x;
+                        buf[2*i+1] = a[i].y;
+                    }
+                    buf2 = new double[2*m];
+                    for(i=0; i<=n-1; i++)
+                    {
+                        buf2[2*i+0] = b[i].x;
+                        buf2[2*i+1] = b[i].y;
+                    }
+                    for(i=n; i<=m-1; i++)
+                    {
+                        buf2[2*i+0] = 0;
+                        buf2[2*i+1] = 0;
+                    }
+                    ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
+                    ftbase.ftbaseexecuteplan(ref buf2, 0, m, ref plan);
+                    for(i=0; i<=m-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;
+                    }
+                    ftbase.ftbaseexecuteplan(ref buf, 0, m, ref plan);
+                    t = (double)(1)/(double)(m);
+                    r = new AP.Complex[m];
+                    for(i=0; i<=m-1; i++)
+                    {
+                        r[i].x = +(t*buf[2*i+0]);
+                        r[i].y = -(t*buf[2*i+1]);
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // M is non-smooth, general code (circular/non-circular):
+                    // * first part is the same for circular and non-circular
+                    //   convolutions. zero padding, FFTs, inverse FFTs
+                    // * second part differs:
+                    //   * for non-circular convolution we just copy array
+                    //   * for circular convolution we add array tail to its head
+                    //
+                    p = ftbase.ftbasefindsmooth(m+n-1);
+                    ftbase.ftbasegeneratecomplexfftplan(p, ref plan);
+                    buf = new double[2*p];
+                    for(i=0; i<=m-1; i++)
+                    {
+                        buf[2*i+0] = a[i].x;
+                        buf[2*i+1] = a[i].y;
+                    }
+                    for(i=m; i<=p-1; i++)
+                    {
+                        buf[2*i+0] = 0;
+                        buf[2*i+1] = 0;
+                    }
+                    buf2 = new double[2*p];
+                    for(i=0; i<=n-1; i++)
+                    {
+                        buf2[2*i+0] = b[i].x;
+                        buf2[2*i+1] = b[i].y;
+                    }
+                    for(i=n; i<=p-1; i++)
+                    {
+                        buf2[2*i+0] = 0;
+                        buf2[2*i+1] = 0;
+                    }
+                    ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
+                    ftbase.ftbaseexecuteplan(ref buf2, 0, p, ref plan);
+                    for(i=0; i<=p-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;
+                    }
+                    ftbase.ftbaseexecuteplan(ref buf, 0, p, ref plan);
+                    t = (double)(1)/(double)(p);
+                    if( circular )
+                    {
+                        
+                        //
+                        // circular, add tail to head
+                        //
+                        r = new AP.Complex[m];
+                        for(i=0; i<=m-1; i++)
+                        {
+                            r[i].x = +(t*buf[2*i+0]);
+                            r[i].y = -(t*buf[2*i+1]);
+                        }
+                        for(i=m; i<=m+n-2; i++)
+                        {
+                            r[i-m].x = r[i-m].x+t*buf[2*i+0];
+                            r[i-m].y = r[i-m].y-t*buf[2*i+1];
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // non-circular, just copy
+                        //
+                        r = new AP.Complex[m+n-1];
+                        for(i=0; i<=m+n-2; i++)
+                        {
+                            r[i].x = +(t*buf[2*i+0]);
+                            r[i].y = -(t*buf[2*i+1]);
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // overlap-add method for
+            // circular and non-circular convolutions.
+            //
+            // First part of code (separate FFTs of input blocks) is the same
+            // for all types of convolution. Second part (overlapping outputs)
+            // differs for different types of convolution. We just copy output
+            // when convolution is non-circular. We wrap it around, if it is
+            // circular.
+            //
+            if( alg==2 )
+            {
+                buf = new double[2*(q+n-1)];
+                
+                //
+                // prepare R
+                //
+                if( circular )
+                {
+                    r = new AP.Complex[m];
+                    for(i=0; i<=m-1; i++)
+                    {
+                        r[i] = 0;
+                    }
+                }
+                else
+                {
+                    r = new AP.Complex[m+n-1];
+                    for(i=0; i<=m+n-2; i++)
+                    {
+                        r[i] = 0;
+                    }
+                }
+                
+                //
+                // pre-calculated FFT(B)
+                //
+                bbuf = new AP.Complex[q+n-1];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    bbuf[i_] = b[i_];
+                }
+                for(j=n; j<=q+n-2; j++)
+                {
+                    bbuf[j] = 0;
+                }
+                fft.fftc1d(ref bbuf, q+n-1);
+                
+                //
+                // prepare FFT plan for chunks of A
+                //
+                ftbase.ftbasegeneratecomplexfftplan(q+n-1, ref plan);
+                
+                //
+                // main overlap-add cycle
+                //
+                i = 0;
+                while( i<=m-1 )
+                {
+                    p = Math.Min(q, m-i);
+                    for(j=0; j<=p-1; j++)
+                    {
+                        buf[2*j+0] = a[i+j].x;
+                        buf[2*j+1] = a[i+j].y;
+                    }
+                    for(j=p; j<=q+n-2; j++)
+                    {
+                        buf[2*j+0] = 0;
+                        buf[2*j+1] = 0;
+                    }
+                    ftbase.ftbaseexecuteplan(ref buf, 0, q+n-1, ref plan);
+                    for(j=0; j<=q+n-2; j++)
+                    {
+                        ax = buf[2*j+0];
+                        ay = buf[2*j+1];
+                        bx = bbuf[j].x;
+                        by = bbuf[j].y;
+                        tx = ax*bx-ay*by;
+                        ty = ax*by+ay*bx;
+                        buf[2*j+0] = tx;
+                        buf[2*j+1] = -ty;
+                    }
+                    ftbase.ftbaseexecuteplan(ref buf, 0, q+n-1, ref plan);
+                    t = (double)(1)/((double)(q+n-1));
+                    if( circular )
+                    {
+                        j1 = Math.Min(i+p+n-2, m-1)-i;
+                        j2 = j1+1;
+                    }
+                    else
+                    {
+                        j1 = p+n-2;
+                        j2 = j1+1;
+                    }
+                    for(j=0; j<=j1; j++)
+                    {
+                        r[i+j].x = r[i+j].x+buf[2*j+0]*t;
+                        r[i+j].y = r[i+j].y-buf[2*j+1]*t;
+                    }
+                    for(j=j2; j<=p+n-2; j++)
+                    {
+                        r[j-j2].x = r[j-j2].x+buf[2*j+0]*t;
+                        r[j-j2].y = r[j-j2].y-buf[2*j+1]*t;
+                    }
+                    i = i+p;
+                }
+                return;
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional real convolution.
+
+        Extended subroutine which allows to choose convolution algorithm.
+        Intended for internal use, ALGLIB users should call ConvR1D().
+
+        INPUT PARAMETERS
+            A   -   array[0..M-1] - complex function to be transformed
+            M   -   problem size
+            B   -   array[0..N-1] - complex function to be transformed
+            N   -   problem size, N<=M
+            Alg -   algorithm type:
+                    *-2     auto-select Q for overlap-add
+                    *-1     auto-select algorithm and parameters
+                    * 0     straightforward formula for small N's
+                    * 1     general FFT-based code
+                    * 2     overlap-add with length Q
+            Q   -   length for overlap-add
+
+        OUTPUT PARAMETERS
+            R   -   convolution: A*B. array[0..N+M-1].
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void convr1dx(ref double[] a,
+            int m,
+            ref double[] b,
+            int n,
+            bool circular,
+            int alg,
+            int q,
+            ref double[] r)
+        {
+            double v = 0;
+            int i = 0;
+            int j = 0;
+            int p = 0;
+            int ptotal = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int j1 = 0;
+            int j2 = 0;
+            double ax = 0;
+            double ay = 0;
+            double bx = 0;
+            double by = 0;
+            double t = 0;
+            double tx = 0;
+            double ty = 0;
+            double flopcand = 0;
+            double flopbest = 0;
+            int algbest = 0;
+            ftbase.ftplan plan = new ftbase.ftplan();
+            double[] buf = new double[0];
+            double[] buf2 = new double[0];
+            double[] buf3 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DX: incorrect N or M!");
+            System.Diagnostics.Debug.Assert(n<=m, "ConvC1DX: N<M assumption is false!");
+            
+            //
+            // handle special cases
+            //
+            if( Math.Min(m, n)<=2 )
+            {
+                alg = 0;
+            }
+            
+            //
+            // Auto-select
+            //
+            if( alg<0 )
+            {
+                
+                //
+                // Initial candidate: straightforward implementation.
+                //
+                // If we want to use auto-fitted overlap-add,
+                // flop count is initialized by large real number - to force
+                // another algorithm selection
+                //
+                algbest = 0;
+                if( alg==-1 )
+                {
+                    flopbest = 0.15*m*n;
+                }
+                else
+                {
+                    flopbest = AP.Math.MaxRealNumber;
+                }
+                
+                //
+                // Another candidate - generic FFT code
+                //
+                if( alg==-1 )
+                {
+                    if( circular & ftbase.ftbaseissmooth(m) & m%2==0 )
+                    {
+                        
+                        //
+                        // special code for circular convolution of a sequence with a smooth length
+                        //
+                        flopcand = 3*ftbase.ftbasegetflopestimate(m/2)+(double)(6*m)/(double)(2);
+                        if( (double)(flopcand)<(double)(flopbest) )
+                        {
+                            algbest = 1;
+                            flopbest = flopcand;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // general cyclic/non-cyclic convolution
+                        //
+                        p = ftbase.ftbasefindsmootheven(m+n-1);
+                        flopcand = 3*ftbase.ftbasegetflopestimate(p/2)+(double)(6*p)/(double)(2);
+                        if( (double)(flopcand)<(double)(flopbest) )
+                        {
+                            algbest = 1;
+                            flopbest = flopcand;
+                        }
+                    }
+                }
+                
+                //
+                // Another candidate - overlap-add
+                //
+                q = 1;
+                ptotal = 1;
+                while( ptotal<n )
+                {
+                    ptotal = ptotal*2;
+                }
+                while( ptotal<=m+n-1 )
+                {
+                    p = ptotal-n+1;
+                    flopcand = (int)Math.Ceiling((double)(m)/(double)(p))*(2*ftbase.ftbasegetflopestimate(ptotal/2)+1*(ptotal/2));
+                    if( (double)(flopcand)<(double)(flopbest) )
+                    {
+                        flopbest = flopcand;
+                        algbest = 2;
+                        q = p;
+                    }
+                    ptotal = ptotal*2;
+                }
+                alg = algbest;
+                convr1dx(ref a, m, ref b, n, circular, alg, q, ref r);
+                return;
+            }
+            
+            //
+            // straightforward formula for
+            // circular and non-circular convolutions.
+            //
+            // Very simple code, no further comments needed.
+            //
+            if( alg==0 )
+            {
+                
+                //
+                // Special case: N=1
+                //
+                if( n==1 )
+                {
+                    r = new double[m];
+                    v = b[0];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        r[i_] = v*a[i_];
+                    }
+                    return;
+                }
+                
+                //
+                // use straightforward formula
+                //
+                if( circular )
+                {
+                    
+                    //
+                    // circular convolution
+                    //
+                    r = new double[m];
+                    v = b[0];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        r[i_] = v*a[i_];
+                    }
+                    for(i=1; i<=n-1; i++)
+                    {
+                        v = b[i];
+                        i1 = 0;
+                        i2 = i-1;
+                        j1 = m-i;
+                        j2 = m-1;
+                        i1_ = (j1) - (i1);
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            r[i_] = r[i_] + v*a[i_+i1_];
+                        }
+                        i1 = i;
+                        i2 = m-1;
+                        j1 = 0;
+                        j2 = m-i-1;
+                        i1_ = (j1) - (i1);
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            r[i_] = r[i_] + v*a[i_+i1_];
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // non-circular convolution
+                    //
+                    r = new double[m+n-1];
+                    for(i=0; i<=m+n-2; i++)
+                    {
+                        r[i] = 0;
+                    }
+                    for(i=0; i<=n-1; i++)
+                    {
+                        v = b[i];
+                        i1_ = (0) - (i);
+                        for(i_=i; i_<=i+m-1;i_++)
+                        {
+                            r[i_] = r[i_] + v*a[i_+i1_];
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // general FFT-based code for
+            // circular and non-circular convolutions.
+            //
+            // First, if convolution is circular, we test whether M is smooth or not.
+            // If it is smooth, we just use M-length FFT to calculate convolution.
+            // If it is not, we calculate non-circular convolution and wrap it arount.
+            //
+            // If convolution is non-circular, we use zero-padding + FFT.
+            //
+            // We assume that M+N-1>2 - we should call small case code otherwise
+            //
+            if( alg==1 )
+            {
+                System.Diagnostics.Debug.Assert(m+n-1>2, "ConvR1DX: internal error!");
+                if( circular & ftbase.ftbaseissmooth(m) & m%2==0 )
+                {
+                    
+                    //
+                    // special code for circular convolution with smooth even M
+                    //
+                    buf = new double[m];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        buf[i_] = a[i_];
+                    }
+                    buf2 = new double[m];
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        buf2[i_] = b[i_];
+                    }
+                    for(i=n; i<=m-1; i++)
+                    {
+                        buf2[i] = 0;
+                    }
+                    buf3 = new double[m];
+                    ftbase.ftbasegeneratecomplexfftplan(m/2, ref plan);
+                    fft.fftr1dinternaleven(ref buf, m, ref buf3, ref plan);
+                    fft.fftr1dinternaleven(ref buf2, m, ref buf3, ref plan);
+                    buf[0] = buf[0]*buf2[0];
+                    buf[1] = buf[1]*buf2[1];
+                    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;
+                    }
+                    fft.fftr1dinvinternaleven(ref buf, m, ref buf3, ref plan);
+                    r = new double[m];
+                    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 = ftbase.ftbasefindsmootheven(m+n-1);
+                    buf = new double[p];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        buf[i_] = a[i_];
+                    }
+                    for(i=m; i<=p-1; i++)
+                    {
+                        buf[i] = 0;
+                    }
+                    buf2 = new double[p];
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        buf2[i_] = b[i_];
+                    }
+                    for(i=n; i<=p-1; i++)
+                    {
+                        buf2[i] = 0;
+                    }
+                    buf3 = new double[p];
+                    ftbase.ftbasegeneratecomplexfftplan(p/2, ref plan);
+                    fft.fftr1dinternaleven(ref buf, p, ref buf3, ref plan);
+                    fft.fftr1dinternaleven(ref buf2, p, ref buf3, ref plan);
+                    buf[0] = buf[0]*buf2[0];
+                    buf[1] = buf[1]*buf2[1];
+                    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;
+                    }
+                    fft.fftr1dinvinternaleven(ref buf, p, ref buf3, ref plan);
+                    if( circular )
+                    {
+                        
+                        //
+                        // circular, add tail to head
+                        //
+                        r = new double[m];
+                        for(i_=0; i_<=m-1;i_++)
+                        {
+                            r[i_] = buf[i_];
+                        }
+                        if( n>=2 )
+                        {
+                            i1_ = (m) - (0);
+                            for(i_=0; i_<=n-2;i_++)
+                            {
+                                r[i_] = r[i_] + buf[i_+i1_];
+                            }
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // non-circular, just copy
+                        //
+                        r = new double[m+n-1];
+                        for(i_=0; i_<=m+n-2;i_++)
+                        {
+                            r[i_] = buf[i_];
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // overlap-add method
+            //
+            if( alg==2 )
+            {
+                System.Diagnostics.Debug.Assert((q+n-1)%2==0, "ConvR1DX: internal error!");
+                buf = new double[q+n-1];
+                buf2 = new double[q+n-1];
+                buf3 = new double[q+n-1];
+                ftbase.ftbasegeneratecomplexfftplan((q+n-1)/2, ref plan);
+                
+                //
+                // prepare R
+                //
+                if( circular )
+                {
+                    r = new double[m];
+                    for(i=0; i<=m-1; i++)
+                    {
+                        r[i] = 0;
+                    }
+                }
+                else
+                {
+                    r = new double[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;
+                }
+                fft.fftr1dinternaleven(ref buf2, q+n-1, ref buf3, ref plan);
+                
+                //
+                // main overlap-add cycle
+                //
+                i = 0;
+                while( i<=m-1 )
+                {
+                    p = Math.Min(q, m-i);
+                    i1_ = (i) - (0);
+                    for(i_=0; i_<=p-1;i_++)
+                    {
+                        buf[i_] = a[i_+i1_];
+                    }
+                    for(j=p; j<=q+n-2; j++)
+                    {
+                        buf[j] = 0;
+                    }
+                    fft.fftr1dinternaleven(ref buf, q+n-1, ref buf3, ref plan);
+                    buf[0] = buf[0]*buf2[0];
+                    buf[1] = buf[1]*buf2[1];
+                    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;
+                    }
+                    fft.fftr1dinvinternaleven(ref buf, q+n-1, ref buf3, ref plan);
+                    if( circular )
+                    {
+                        j1 = Math.Min(i+p+n-2, m-1)-i;
+                        j2 = j1+1;
+                    }
+                    else
+                    {
+                        j1 = p+n-2;
+                        j2 = j1+1;
+                    }
+                    i1_ = (0) - (i);
+                    for(i_=i; i_<=i+j1;i_++)
+                    {
+                        r[i_] = r[i_] + buf[i_+i1_];
+                    }
+                    if( p+n-2>=j2 )
+                    {
+                        i1_ = (j2) - (0);
+                        for(i_=0; i_<=p+n-2-j2;i_++)
+                        {
+                            r[i_] = r[i_] + buf[i_+i1_];
+                        }
+                    }
+                    i = i+p;
+                }
+                return;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/corr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/corr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/corr.cs	(revision 2645)
@@ -0,0 +1,364 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class corr
+    {
+        /*************************************************************************
+        1-dimensional complex cross-correlation.
+
+        For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
+
+        Correlation is calculated using reduction to  convolution.  Algorithm with
+        max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
+        about performance).
+
+        IMPORTANT:
+            for  historical reasons subroutine accepts its parameters in  reversed
+            order: CorrC1D(Signal, Pattern) = Pattern x Signal (using  traditional
+            definition of cross-correlation, denoting cross-correlation as "x").
+
+        INPUT PARAMETERS
+            Signal  -   array[0..N-1] - complex function to be transformed,
+                        signal containing pattern
+            N       -   problem size
+            Pattern -   array[0..M-1] - complex function to be transformed,
+                        pattern to search withing signal
+            M       -   problem size
+
+        OUTPUT PARAMETERS
+            R       -   cross-correlation, array[0..N+M-2]:
+                        * positive lags are stored in R[0..N-1],
+                          R[i] = sum(conj(pattern[j])*signal[i+j]
+                        * negative lags are stored in R[N..N+M-2],
+                          R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
+
+        NOTE:
+            It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
+        on [-K..M-1],  you can still use this subroutine, just shift result by K.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void corrc1d(ref AP.Complex[] signal,
+            int n,
+            ref AP.Complex[] pattern,
+            int m,
+            ref AP.Complex[] r)
+        {
+            AP.Complex[] p = new AP.Complex[0];
+            AP.Complex[] b = new AP.Complex[0];
+            int i = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "CorrC1D: incorrect N or M!");
+            p = new AP.Complex[m];
+            for(i=0; i<=m-1; i++)
+            {
+                p[m-1-i] = AP.Math.Conj(pattern[i]);
+            }
+            conv.convc1d(ref p, m, ref signal, n, ref b);
+            r = new AP.Complex[m+n-1];
+            i1_ = (m-1) - (0);
+            for(i_=0; i_<=n-1;i_++)
+            {
+                r[i_] = b[i_+i1_];
+            }
+            if( m+n-2>=n )
+            {
+                i1_ = (0) - (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].
+
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void corrc1dcircular(ref AP.Complex[] signal,
+            int m,
+            ref AP.Complex[] pattern,
+            int n,
+            ref AP.Complex[] c)
+        {
+            AP.Complex[] p = new AP.Complex[0];
+            AP.Complex[] b = new AP.Complex[0];
+            int i1 = 0;
+            int i2 = 0;
+            int i = 0;
+            int j2 = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircular: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer (at least - not shorter) that B.
+            //
+            if( m<n )
+            {
+                b = new AP.Complex[m];
+                for(i1=0; i1<=m-1; i1++)
+                {
+                    b[i1] = 0;
+                }
+                i1 = 0;
+                while( i1<n )
+                {
+                    i2 = Math.Min(i1+m-1, n-1);
+                    j2 = i2-i1;
+                    i1_ = (i1) - (0);
+                    for(i_=0; i_<=j2;i_++)
+                    {
+                        b[i_] = b[i_] + pattern[i_+i1_];
+                    }
+                    i1 = i1+m;
+                }
+                corrc1dcircular(ref signal, m, ref b, m, ref c);
+                return;
+            }
+            
+            //
+            // Task is normalized
+            //
+            p = new AP.Complex[n];
+            for(i=0; i<=n-1; i++)
+            {
+                p[n-1-i] = AP.Math.Conj(pattern[i]);
+            }
+            conv.convc1dcircular(ref signal, m, ref p, n, ref b);
+            c = new AP.Complex[m];
+            i1_ = (n-1) - (0);
+            for(i_=0; i_<=m-n;i_++)
+            {
+                c[i_] = b[i_+i1_];
+            }
+            if( m-n+1<=m-1 )
+            {
+                i1_ = (0) - (m-n+1);
+                for(i_=m-n+1; i_<=m-1;i_++)
+                {
+                    c[i_] = b[i_+i1_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional real cross-correlation.
+
+        For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
+
+        Correlation is calculated using reduction to  convolution.  Algorithm with
+        max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
+        about performance).
+
+        IMPORTANT:
+            for  historical reasons subroutine accepts its parameters in  reversed
+            order: CorrR1D(Signal, Pattern) = Pattern x Signal (using  traditional
+            definition of cross-correlation, denoting cross-correlation as "x").
+
+        INPUT PARAMETERS
+            Signal  -   array[0..N-1] - real function to be transformed,
+                        signal containing pattern
+            N       -   problem size
+            Pattern -   array[0..M-1] - real function to be transformed,
+                        pattern to search withing signal
+            M       -   problem size
+
+        OUTPUT PARAMETERS
+            R       -   cross-correlation, array[0..N+M-2]:
+                        * positive lags are stored in R[0..N-1],
+                          R[i] = sum(pattern[j]*signal[i+j]
+                        * negative lags are stored in R[N..N+M-2],
+                          R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
+
+        NOTE:
+            It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
+        on [-K..M-1],  you can still use this subroutine, just shift result by K.
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void corrr1d(ref double[] signal,
+            int n,
+            ref double[] pattern,
+            int m,
+            ref double[] r)
+        {
+            double[] p = new double[0];
+            double[] b = new double[0];
+            int i = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "CorrR1D: incorrect N or M!");
+            p = new double[m];
+            for(i=0; i<=m-1; i++)
+            {
+                p[m-1-i] = pattern[i];
+            }
+            conv.convr1d(ref p, m, ref signal, n, ref b);
+            r = new double[m+n-1];
+            i1_ = (m-1) - (0);
+            for(i_=0; i_<=n-1;i_++)
+            {
+                r[i_] = b[i_+i1_];
+            }
+            if( m+n-2>=n )
+            {
+                i1_ = (0) - (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].
+
+
+          -- ALGLIB --
+             Copyright 21.07.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void corrr1dcircular(ref double[] signal,
+            int m,
+            ref double[] pattern,
+            int n,
+            ref double[] c)
+        {
+            double[] p = new double[0];
+            double[] b = new double[0];
+            int i1 = 0;
+            int i2 = 0;
+            int i = 0;
+            int j2 = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & m>0, "ConvC1DCircular: incorrect N or M!");
+            
+            //
+            // normalize task: make M>=N,
+            // so A will be longer (at least - not shorter) that B.
+            //
+            if( m<n )
+            {
+                b = new double[m];
+                for(i1=0; i1<=m-1; i1++)
+                {
+                    b[i1] = 0;
+                }
+                i1 = 0;
+                while( i1<n )
+                {
+                    i2 = Math.Min(i1+m-1, n-1);
+                    j2 = i2-i1;
+                    i1_ = (i1) - (0);
+                    for(i_=0; i_<=j2;i_++)
+                    {
+                        b[i_] = b[i_] + pattern[i_+i1_];
+                    }
+                    i1 = i1+m;
+                }
+                corrr1dcircular(ref signal, m, ref b, m, ref c);
+                return;
+            }
+            
+            //
+            // Task is normalized
+            //
+            p = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                p[n-1-i] = pattern[i];
+            }
+            conv.convr1dcircular(ref signal, m, ref p, n, ref b);
+            c = new double[m];
+            i1_ = (n-1) - (0);
+            for(i_=0; i_<=m-n;i_++)
+            {
+                c[i_] = b[i_+i1_];
+            }
+            if( m-n+1<=m-1 )
+            {
+                i1_ = (0) - (m-n+1);
+                for(i_=m-n+1; i_<=m-1;i_++)
+                {
+                    c[i_] = b[i_+i1_];
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/correlation.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/correlation.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/correlation.cs	(revision 2645)
@@ -0,0 +1,272 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class correlation
+    {
+        /*************************************************************************
+        Pearson product-moment correlation coefficient
+
+        Input parameters:
+            X       -   sample 1 (array indexes: [0..N-1])
+            Y       -   sample 2 (array indexes: [0..N-1])
+            N       -   sample size.
+
+        Result:
+            Pearson product-moment correlation coefficient
+
+          -- ALGLIB --
+             Copyright 09.04.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double pearsoncorrelation(ref double[] x,
+            ref double[] y,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            double xmean = 0;
+            double ymean = 0;
+            double s = 0;
+            double xv = 0;
+            double yv = 0;
+            double t1 = 0;
+            double t2 = 0;
+
+            xv = 0;
+            yv = 0;
+            if( n<=1 )
+            {
+                result = 0;
+                return result;
+            }
+            
+            //
+            // Mean
+            //
+            xmean = 0;
+            ymean = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xmean = xmean+x[i];
+                ymean = ymean+y[i];
+            }
+            xmean = xmean/n;
+            ymean = ymean/n;
+            
+            //
+            // numerator and denominator
+            //
+            s = 0;
+            xv = 0;
+            yv = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                t1 = x[i]-xmean;
+                t2 = y[i]-ymean;
+                xv = xv+AP.Math.Sqr(t1);
+                yv = yv+AP.Math.Sqr(t2);
+                s = s+t1*t2;
+            }
+            if( (double)(xv)==(double)(0) | (double)(yv)==(double)(0) )
+            {
+                result = 0;
+            }
+            else
+            {
+                result = s/(Math.Sqrt(xv)*Math.Sqrt(yv));
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Spearman's rank correlation coefficient
+
+        Input parameters:
+            X       -   sample 1 (array indexes: [0..N-1])
+            Y       -   sample 2 (array indexes: [0..N-1])
+            N       -   sample size.
+
+        Result:
+            Spearman's rank correlation coefficient
+
+          -- ALGLIB --
+             Copyright 09.04.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double spearmanrankcorrelation(double[] x,
+            double[] y,
+            int n)
+        {
+            double result = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            rankx(ref x, n);
+            rankx(ref y, n);
+            result = pearsoncorrelation(ref x, ref y, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal ranking subroutine
+        *************************************************************************/
+        private static void rankx(ref double[] x,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            int tmpi = 0;
+            double[] r = new double[0];
+            int[] c = new int[0];
+
+            
+            //
+            // Prepare
+            //
+            if( n<=1 )
+            {
+                x[0] = 1;
+                return;
+            }
+            r = new double[n-1+1];
+            c = new int[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                r[i] = x[i];
+                c[i] = i;
+            }
+            
+            //
+            // sort {R, C}
+            //
+            if( n!=1 )
+            {
+                i = 2;
+                do
+                {
+                    t = i;
+                    while( t!=1 )
+                    {
+                        k = t/2;
+                        if( (double)(r[k-1])>=(double)(r[t-1]) )
+                        {
+                            t = 1;
+                        }
+                        else
+                        {
+                            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 = i+1;
+                }
+                while( i<=n );
+                i = n-1;
+                do
+                {
+                    tmp = r[i];
+                    r[i] = r[0];
+                    r[0] = tmp;
+                    tmpi = c[i];
+                    c[i] = c[0];
+                    c[0] = tmpi;
+                    t = 1;
+                    while( t!=0 )
+                    {
+                        k = 2*t;
+                        if( k>i )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            if( k<i )
+                            {
+                                if( (double)(r[k])>(double)(r[k-1]) )
+                                {
+                                    k = k+1;
+                                }
+                            }
+                            if( (double)(r[t-1])>=(double)(r[k-1]) )
+                            {
+                                t = 0;
+                            }
+                            else
+                            {
+                                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 = i-1;
+                }
+                while( i>=1 );
+            }
+            
+            //
+            // compute tied ranks
+            //
+            i = 0;
+            while( i<=n-1 )
+            {
+                j = i+1;
+                while( j<=n-1 )
+                {
+                    if( (double)(r[j])!=(double)(r[i]) )
+                    {
+                        break;
+                    }
+                    j = j+1;
+                }
+                for(k=i; k<=j-1; k++)
+                {
+                    r[k] = 1+((double)(i+j-1))/(double)(2);
+                }
+                i = j;
+            }
+            
+            //
+            // back to x
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                x[c[i]] = r[i];
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/correlationtests.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/correlationtests.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/correlationtests.cs	(revision 2645)
@@ -0,0 +1,710 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class correlationtests
+    {
+        /*************************************************************************
+        Pearson's correlation coefficient significance test
+
+        This test checks hypotheses about whether X  and  Y  are  samples  of  two
+        continuous  distributions  having  zero  correlation  or   whether   their
+        correlation is non-zero.
+
+        The following tests are performed:
+            * two-tailed test (null hypothesis - X and Y have zero correlation)
+            * left-tailed test (null hypothesis - the correlation  coefficient  is
+              greater than or equal to 0)
+            * right-tailed test (null hypothesis - the correlation coefficient  is
+              less than or equal to 0).
+
+        Requirements:
+            * the number of elements in each sample is not less than 5
+            * normality of distributions of X and Y.
+
+        Input parameters:
+            R   -   Pearson's correlation coefficient for X and Y
+            N   -   number of elements in samples, N>=5.
+
+        Output parameters:
+            BothTails   -   p-value for two-tailed test.
+                            If BothTails is less than the given significance level
+                            the null hypothesis is rejected.
+            LeftTail    -   p-value for left-tailed test.
+                            If LeftTail is less than the given significance level,
+                            the null hypothesis is rejected.
+            RightTail   -   p-value for right-tailed test.
+                            If RightTail is less than the given significance level
+                            the null hypothesis is rejected.
+
+          -- ALGLIB --
+             Copyright 09.04.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void pearsoncorrelationsignificance(double r,
+            int n,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            double t = 0;
+            double p = 0;
+
+            
+            //
+            // Some special cases
+            //
+            if( (double)(r)>=(double)(1) )
+            {
+                bothtails = 0.0;
+                lefttail = 1.0;
+                righttail = 0.0;
+                return;
+            }
+            if( (double)(r)<=(double)(-1) )
+            {
+                bothtails = 0.0;
+                lefttail = 0.0;
+                righttail = 1.0;
+                return;
+            }
+            if( n<5 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // General case
+            //
+            t = r*Math.Sqrt((n-2)/(1-AP.Math.Sqr(r)));
+            p = studenttdistr.studenttdistribution(n-2, t);
+            bothtails = 2*Math.Min(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.
+
+          -- ALGLIB --
+             Copyright 09.04.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spearmanrankcorrelationsignificance(double r,
+            int n,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            double t = 0;
+            double p = 0;
+
+            
+            //
+            // Special case
+            //
+            if( n<5 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // General case
+            //
+            if( (double)(r)>=(double)(1) )
+            {
+                t = 1.0E10;
+            }
+            else
+            {
+                if( (double)(r)<=(double)(-1) )
+                {
+                    t = -1.0E10;
+                }
+                else
+                {
+                    t = r*Math.Sqrt((n-2)/(1-AP.Math.Sqr(r)));
+                }
+            }
+            if( (double)(t)<(double)(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;
+            }
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5)
+        *************************************************************************/
+        private static double spearmantail5(double s)
+        {
+            double result = 0;
+
+            if( (double)(s)<(double)(0.000e+00) )
+            {
+                result = studenttdistr.studenttdistribution(3, -s);
+                return result;
+            }
+            if( (double)(s)>=(double)(3.580e+00) )
+            {
+                result = 8.304e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.322e+00) )
+            {
+                result = 4.163e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.704e+00) )
+            {
+                result = 6.641e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.303e+00) )
+            {
+                result = 1.164e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.003e+00) )
+            {
+                result = 1.748e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(7.584e-01) )
+            {
+                result = 2.249e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(5.468e-01) )
+            {
+                result = 2.581e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.555e-01) )
+            {
+                result = 3.413e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.759e-01) )
+            {
+                result = 3.911e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.741e-03) )
+            {
+                result = 4.747e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(0.000e+00) )
+            {
+                result = 5.248e-01;
+                return result;
+            }
+            result = 0;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6)
+        *************************************************************************/
+        private static double spearmantail6(double s)
+        {
+            double result = 0;
+
+            if( (double)(s)<(double)(1.001e+00) )
+            {
+                result = studenttdistr.studenttdistribution(4, -s);
+                return result;
+            }
+            if( (double)(s)>=(double)(5.663e+00) )
+            {
+                result = 1.366e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.834e+00) )
+            {
+                result = 8.350e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.968e+00) )
+            {
+                result = 1.668e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.430e+00) )
+            {
+                result = 2.921e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.045e+00) )
+            {
+                result = 5.144e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.747e+00) )
+            {
+                result = 6.797e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.502e+00) )
+            {
+                result = 8.752e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.295e+00) )
+            {
+                result = 1.210e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.113e+00) )
+            {
+                result = 1.487e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.001e+00) )
+            {
+                result = 1.780e-01;
+                return result;
+            }
+            result = 0;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7)
+        *************************************************************************/
+        private static double spearmantail7(double s)
+        {
+            double result = 0;
+
+            if( (double)(s)<(double)(1.001e+00) )
+            {
+                result = studenttdistr.studenttdistribution(5, -s);
+                return result;
+            }
+            if( (double)(s)>=(double)(8.159e+00) )
+            {
+                result = 2.081e-04;
+                return result;
+            }
+            if( (double)(s)>=(double)(5.620e+00) )
+            {
+                result = 1.393e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(4.445e+00) )
+            {
+                result = 3.398e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.728e+00) )
+            {
+                result = 6.187e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.226e+00) )
+            {
+                result = 1.200e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.844e+00) )
+            {
+                result = 1.712e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.539e+00) )
+            {
+                result = 2.408e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.285e+00) )
+            {
+                result = 3.320e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.068e+00) )
+            {
+                result = 4.406e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.879e+00) )
+            {
+                result = 5.478e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.710e+00) )
+            {
+                result = 6.946e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.559e+00) )
+            {
+                result = 8.331e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.420e+00) )
+            {
+                result = 1.001e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.292e+00) )
+            {
+                result = 1.180e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.173e+00) )
+            {
+                result = 1.335e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.062e+00) )
+            {
+                result = 1.513e-01;
+                return result;
+            }
+            if( (double)(s)>=(double)(1.001e+00) )
+            {
+                result = 1.770e-01;
+                return result;
+            }
+            result = 0;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8)
+        *************************************************************************/
+        private static double spearmantail8(double s)
+        {
+            double result = 0;
+
+            if( (double)(s)<(double)(2.001e+00) )
+            {
+                result = studenttdistr.studenttdistribution(6, -s);
+                return result;
+            }
+            if( (double)(s)>=(double)(1.103e+01) )
+            {
+                result = 2.194e-05;
+                return result;
+            }
+            if( (double)(s)>=(double)(7.685e+00) )
+            {
+                result = 2.008e-04;
+                return result;
+            }
+            if( (double)(s)>=(double)(6.143e+00) )
+            {
+                result = 5.686e-04;
+                return result;
+            }
+            if( (double)(s)>=(double)(5.213e+00) )
+            {
+                result = 1.138e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(4.567e+00) )
+            {
+                result = 2.310e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(4.081e+00) )
+            {
+                result = 3.634e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.697e+00) )
+            {
+                result = 5.369e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.381e+00) )
+            {
+                result = 7.708e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.114e+00) )
+            {
+                result = 1.087e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.884e+00) )
+            {
+                result = 1.397e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.682e+00) )
+            {
+                result = 1.838e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.502e+00) )
+            {
+                result = 2.288e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.340e+00) )
+            {
+                result = 2.883e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.192e+00) )
+            {
+                result = 3.469e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.057e+00) )
+            {
+                result = 4.144e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.001e+00) )
+            {
+                result = 4.804e-02;
+                return result;
+            }
+            result = 0;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9)
+        *************************************************************************/
+        private static double spearmantail9(double s)
+        {
+            double result = 0;
+
+            if( (double)(s)<(double)(2.001e+00) )
+            {
+                result = studenttdistr.studenttdistribution(7, -s);
+                return result;
+            }
+            if( (double)(s)>=(double)(9.989e+00) )
+            {
+                result = 2.306e-05;
+                return result;
+            }
+            if( (double)(s)>=(double)(8.069e+00) )
+            {
+                result = 8.167e-05;
+                return result;
+            }
+            if( (double)(s)>=(double)(6.890e+00) )
+            {
+                result = 1.744e-04;
+                return result;
+            }
+            if( (double)(s)>=(double)(6.077e+00) )
+            {
+                result = 3.625e-04;
+                return result;
+            }
+            if( (double)(s)>=(double)(5.469e+00) )
+            {
+                result = 6.450e-04;
+                return result;
+            }
+            if( (double)(s)>=(double)(4.991e+00) )
+            {
+                result = 1.001e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(4.600e+00) )
+            {
+                result = 1.514e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(4.272e+00) )
+            {
+                result = 2.213e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.991e+00) )
+            {
+                result = 2.990e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.746e+00) )
+            {
+                result = 4.101e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.530e+00) )
+            {
+                result = 5.355e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.336e+00) )
+            {
+                result = 6.887e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.161e+00) )
+            {
+                result = 8.598e-03;
+                return result;
+            }
+            if( (double)(s)>=(double)(3.002e+00) )
+            {
+                result = 1.065e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.855e+00) )
+            {
+                result = 1.268e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.720e+00) )
+            {
+                result = 1.552e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.595e+00) )
+            {
+                result = 1.836e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.477e+00) )
+            {
+                result = 2.158e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.368e+00) )
+            {
+                result = 2.512e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.264e+00) )
+            {
+                result = 2.942e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.166e+00) )
+            {
+                result = 3.325e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.073e+00) )
+            {
+                result = 3.800e-02;
+                return result;
+            }
+            if( (double)(s)>=(double)(2.001e+00) )
+            {
+                result = 4.285e-02;
+                return result;
+            }
+            result = 0;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(T,N), accepts T<0
+        *************************************************************************/
+        private static double spearmantail(double t,
+            int n)
+        {
+            double result = 0;
+
+            if( n==5 )
+            {
+                result = spearmantail5(-t);
+                return result;
+            }
+            if( n==6 )
+            {
+                result = spearmantail6(-t);
+                return result;
+            }
+            if( n==7 )
+            {
+                result = spearmantail7(-t);
+                return result;
+            }
+            if( n==8 )
+            {
+                result = spearmantail8(-t);
+                return result;
+            }
+            if( n==9 )
+            {
+                result = spearmantail9(-t);
+                return result;
+            }
+            result = studenttdistr.studenttdistribution(n-2, t);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cqr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cqr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/cqr.cs	(revision 2645)
@@ -0,0 +1,437 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class cqr
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static void cmatrixqr(ref AP.Complex[,] a,
+            int m,
+            int n,
+            ref AP.Complex[] tau)
+        {
+            AP.Complex[] work = new AP.Complex[0];
+            AP.Complex[] t = new AP.Complex[0];
+            int i = 0;
+            int k = 0;
+            int mmi = 0;
+            int minmn = 0;
+            AP.Complex tmp = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            minmn = Math.Min(m, n);
+            if( minmn<=0 )
+            {
+                return;
+            }
+            work = new AP.Complex[n-1+1];
+            t = new AP.Complex[m+1];
+            tau = new AP.Complex[minmn-1+1];
+            
+            //
+            // Test the input arguments
+            //
+            k = Math.Min(m, n);
+            for(i=0; i<=k-1; i++)
+            {
+                
+                //
+                // Generate elementary reflector H(i) to annihilate A(i+1:m,i)
+                //
+                mmi = m-i;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=mmi;i_++)
+                {
+                    t[i_] = a[i_+i1_,i];
+                }
+                creflections.complexgeneratereflection(ref t, mmi, ref tmp);
+                tau[i] = tmp;
+                i1_ = (1) - (i);
+                for(i_=i; i_<=m-1;i_++)
+                {
+                    a[i_,i] = t[i_+i1_];
+                }
+                t[1] = 1;
+                if( i<n-1 )
+                {
+                    
+                    //
+                    // Apply H'(i) to A(i:m,i+1:n) from the left
+                    //
+                    creflections.complexapplyreflectionfromtheleft(ref a, AP.Math.Conj(tau[i]), ref t, i, m-1, i+1, n-1, ref work);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Partial unpacking of matrix Q from QR decomposition of a complex matrix A.
+
+        Input parameters:
+            QR          -   matrices Q and R in compact form.
+                            Output of CMatrixQR subroutine .
+            M           -   number of rows in matrix A. M>=0.
+            N           -   number of rows in matrix A. N>=0.
+            Tau         -   scalar factors which are used to form Q.
+                            Output of CMatrixQR subroutine .
+            QColumns    -   required number of columns in matrix Q. M>=QColumns>=0.
+
+        Output parameters:
+            Q           -   first QColumns columns of matrix Q.
+                            Array whose index ranges within [0..M-1, 0..QColumns-1].
+                            If QColumns=0, array isn't changed.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void cmatrixqrunpackq(ref AP.Complex[,] qr,
+            int m,
+            int n,
+            ref AP.Complex[] tau,
+            int qcolumns,
+            ref AP.Complex[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int minmn = 0;
+            AP.Complex[] v = new AP.Complex[0];
+            AP.Complex[] work = new AP.Complex[0];
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!");
+            if( m<=0 | n<=0 | qcolumns<=0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            minmn = Math.Min(m, n);
+            k = Math.Min(minmn, qcolumns);
+            q = new AP.Complex[m-1+1, qcolumns-1+1];
+            v = new AP.Complex[m+1];
+            work = new AP.Complex[qcolumns-1+1];
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=qcolumns-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=k-1; i>=0; i--)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                vm = m-i;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=vm;i_++)
+                {
+                    v[i_] = qr[i_+i1_,i];
+                }
+                v[1] = 1;
+                creflections.complexapplyreflectionfromtheleft(ref q, tau[i], ref v, i, m-1, 0, qcolumns-1, ref work);
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacking of matrix R from the QR decomposition of a matrix A
+
+        Input parameters:
+            A       -   matrices Q and R in compact form.
+                        Output of CMatrixQR subroutine.
+            M       -   number of rows in given matrix A. M>=0.
+            N       -   number of columns in given matrix A. N>=0.
+
+        Output parameters:
+            R       -   matrix R, array[0..M-1, 0..N-1].
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void cmatrixqrunpackr(ref AP.Complex[,] a,
+            int m,
+            int n,
+            ref AP.Complex[,] r)
+        {
+            int i = 0;
+            int k = 0;
+            int i_ = 0;
+
+            if( m<=0 | n<=0 )
+            {
+                return;
+            }
+            k = Math.Min(m, n);
+            r = new AP.Complex[m-1+1, n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                r[0,i] = 0;
+            }
+            for(i=1; i<=m-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    r[i,i_] = r[0,i_];
+                }
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                for(i_=i; i_<=n-1;i_++)
+                {
+                    r[i,i_] = a[i,i_];
+                }
+            }
+        }
+
+
+        public static void complexqrdecomposition(ref AP.Complex[,] a,
+            int m,
+            int n,
+            ref AP.Complex[] tau)
+        {
+            AP.Complex[] work = new AP.Complex[0];
+            AP.Complex[] t = new AP.Complex[0];
+            int i = 0;
+            int k = 0;
+            int mmip1 = 0;
+            int minmn = 0;
+            AP.Complex tmp = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            minmn = Math.Min(m, n);
+            work = new AP.Complex[n+1];
+            t = new AP.Complex[m+1];
+            tau = new AP.Complex[minmn+1];
+            
+            //
+            // Test the input arguments
+            //
+            k = Math.Min(m, n);
+            for(i=1; i<=k; i++)
+            {
+                
+                //
+                // Generate elementary reflector H(i) to annihilate A(i+1:m,i)
+                //
+                mmip1 = m-i+1;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=mmip1;i_++)
+                {
+                    t[i_] = a[i_+i1_,i];
+                }
+                creflections.complexgeneratereflection(ref t, mmip1, ref tmp);
+                tau[i] = tmp;
+                i1_ = (1) - (i);
+                for(i_=i; i_<=m;i_++)
+                {
+                    a[i_,i] = t[i_+i1_];
+                }
+                t[1] = 1;
+                if( i<n )
+                {
+                    
+                    //
+                    // Apply H'(i) to A(i:m,i+1:n) from the left
+                    //
+                    creflections.complexapplyreflectionfromtheleft(ref a, AP.Math.Conj(tau[i]), ref t, i, m, i+1, n, ref work);
+                }
+            }
+        }
+
+
+        public static void complexunpackqfromqr(ref AP.Complex[,] qr,
+            int m,
+            int n,
+            ref AP.Complex[] tau,
+            int qcolumns,
+            ref AP.Complex[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int minmn = 0;
+            AP.Complex[] v = new AP.Complex[0];
+            AP.Complex[] work = new AP.Complex[0];
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!");
+            if( m==0 | n==0 | qcolumns==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            minmn = Math.Min(m, n);
+            k = Math.Min(minmn, qcolumns);
+            q = new AP.Complex[m+1, qcolumns+1];
+            v = new AP.Complex[m+1];
+            work = new AP.Complex[qcolumns+1];
+            for(i=1; i<=m; i++)
+            {
+                for(j=1; j<=qcolumns; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=k; i>=1; i--)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                vm = m-i+1;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=vm;i_++)
+                {
+                    v[i_] = qr[i_+i1_,i];
+                }
+                v[1] = 1;
+                creflections.complexapplyreflectionfromtheleft(ref q, tau[i], ref v, i, m, 1, qcolumns, ref work);
+            }
+        }
+
+
+        public static void complexqrdecompositionunpacked(AP.Complex[,] a,
+            int m,
+            int n,
+            ref AP.Complex[,] q,
+            ref AP.Complex[,] r)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int l = 0;
+            int vm = 0;
+            AP.Complex[] tau = new AP.Complex[0];
+            AP.Complex[] work = new AP.Complex[0];
+            AP.Complex[] v = new AP.Complex[0];
+            double tmp = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            k = Math.Min(m, n);
+            if( n<=0 )
+            {
+                return;
+            }
+            work = new AP.Complex[m+1];
+            v = new AP.Complex[m+1];
+            q = new AP.Complex[m+1, m+1];
+            r = new AP.Complex[m+1, n+1];
+            
+            //
+            // QRDecomposition
+            //
+            complexqrdecomposition(ref a, m, n, ref tau);
+            
+            //
+            // R
+            //
+            for(i=1; i<=n; i++)
+            {
+                r[1,i] = 0;
+            }
+            for(i=2; i<=m; i++)
+            {
+                for(i_=1; i_<=n;i_++)
+                {
+                    r[i,i_] = r[1,i_];
+                }
+            }
+            for(i=1; i<=k; i++)
+            {
+                for(i_=i; i_<=n;i_++)
+                {
+                    r[i,i_] = a[i,i_];
+                }
+            }
+            
+            //
+            // Q
+            //
+            complexunpackqfromqr(ref a, m, n, ref tau, m, ref q);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/crcond.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/crcond.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/crcond.cs	(revision 2645)
@@ -0,0 +1,783 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class crcond
+    {
+        /*************************************************************************
+        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))
+        *************************************************************************/
+        public static double cmatrixrcond1(ref AP.Complex[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            AP.Complex[,] a1 = new AP.Complex[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "CMatrixRCond1: N<1!");
+            a1 = new AP.Complex[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = a[i-1,i_+i1_];
+                }
+            }
+            result = complexrcond1(a1, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Estimate of the condition number of a matrix given by its LU decomposition (1-norm)
+
+        The algorithm calculates a lower bound of the condition number. In this case,
+        the algorithm does not return a lower bound of the condition number, but an
+        inverse number (to avoid an overflow in case of a singular matrix).
+
+        Input parameters:
+            LUDcmp      -   LU decomposition of a matrix in compact form. Output of
+                            the CMatrixLU subroutine.
+            N           -   size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double cmatrixlurcond1(ref AP.Complex[,] ludcmp,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            AP.Complex[,] a1 = new AP.Complex[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "CMatrixLURCond1: N<1!");
+            a1 = new AP.Complex[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = ludcmp[i-1,i_+i1_];
+                }
+            }
+            result = complexrcond1lu(ref a1, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Estimate of a matrix condition number (infinity-norm).
+
+        The algorithm calculates a lower bound of the condition number. In this case,
+        the algorithm does not return a lower bound of the condition number, but an
+        inverse number (to avoid an overflow in case of a singular matrix).
+
+        Input parameters:
+            A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
+            N   -   size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double cmatrixrcondinf(ref AP.Complex[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            AP.Complex[,] a1 = new AP.Complex[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "CMatrixRCondInf: N<1!");
+            a1 = new AP.Complex[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = a[i-1,i_+i1_];
+                }
+            }
+            result = complexrcondinf(a1, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Estimate of the condition number of a matrix given by its LU decomposition
+        (infinity norm).
+
+        The algorithm calculates a lower bound of the condition number. In this case,
+        the algorithm does not return a lower bound of the condition number, but an
+        inverse number (to avoid an overflow in case of a singular matrix).
+
+        Input parameters:
+            LUDcmp  -   LU decomposition of a matrix in compact form. Output of
+                        the CMatrixLU subroutine.
+            N       -   size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double cmatrixlurcondinf(ref AP.Complex[,] ludcmp,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            AP.Complex[,] a1 = new AP.Complex[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "CMatrixLURCondInf: N<1!");
+            a1 = new AP.Complex[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = ludcmp[i-1,i_+i1_];
+                }
+            }
+            result = complexrcondinflu(ref a1, n);
+            return result;
+        }
+
+
+        public static double complexrcond1(AP.Complex[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a = (AP.Complex[,])a.Clone();
+
+            nrm = 0;
+            for(j=1; j<=n; j++)
+            {
+                v = 0;
+                for(i=1; i<=n; i++)
+                {
+                    v = v+AP.Math.AbsComplex(a[i,j]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            clu.complexludecomposition(ref a, n, n, ref pivots);
+            internalestimatecomplexrcondlu(ref a, n, true, true, nrm, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double complexrcond1lu(ref AP.Complex[,] lu,
+            int n)
+        {
+            double result = 0;
+            double v = 0;
+
+            internalestimatecomplexrcondlu(ref lu, n, true, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double complexrcondinf(AP.Complex[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a = (AP.Complex[,])a.Clone();
+
+            nrm = 0;
+            for(i=1; i<=n; i++)
+            {
+                v = 0;
+                for(j=1; j<=n; j++)
+                {
+                    v = v+AP.Math.AbsComplex(a[i,j]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            clu.complexludecomposition(ref a, n, n, ref pivots);
+            internalestimatecomplexrcondlu(ref a, n, false, true, nrm, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double complexrcondinflu(ref AP.Complex[,] lu,
+            int n)
+        {
+            double result = 0;
+            double v = 0;
+
+            internalestimatecomplexrcondlu(ref lu, n, false, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static void internalestimatecomplexrcondlu(ref AP.Complex[,] lu,
+            int n,
+            bool onenorm,
+            bool isanormprovided,
+            double anorm,
+            ref double rcond)
+        {
+            AP.Complex[] cwork1 = new AP.Complex[0];
+            AP.Complex[] cwork2 = new AP.Complex[0];
+            AP.Complex[] cwork3 = new AP.Complex[0];
+            AP.Complex[] cwork4 = new AP.Complex[0];
+            int[] isave = new int[0];
+            double[] rsave = new double[0];
+            int kase = 0;
+            int kase1 = 0;
+            double ainvnm = 0;
+            double smlnum = 0;
+            bool cw = new bool();
+            AP.Complex v = 0;
+            int i = 0;
+            int i_ = 0;
+
+            if( n<=0 )
+            {
+                return;
+            }
+            cwork1 = new AP.Complex[n+1];
+            cwork2 = new AP.Complex[n+1];
+            cwork3 = new AP.Complex[n+1];
+            cwork4 = new AP.Complex[n+1];
+            isave = new int[4+1];
+            rsave = new double[3+1];
+            rcond = 0;
+            if( n==0 )
+            {
+                rcond = 1;
+                return;
+            }
+            smlnum = AP.Math.MinRealNumber;
+            
+            //
+            // Estimate the norm of inv(A).
+            //
+            if( !isanormprovided )
+            {
+                anorm = 0;
+                if( onenorm )
+                {
+                    kase1 = 1;
+                }
+                else
+                {
+                    kase1 = 2;
+                }
+                kase = 0;
+                do
+                {
+                    internalcomplexrcondestimatenorm(n, ref cwork4, ref cwork1, ref anorm, ref kase, ref isave, ref rsave);
+                    if( kase!=0 )
+                    {
+                        if( kase==kase1 )
+                        {
+                            
+                            //
+                            // Multiply by U
+                            //
+                            for(i=1; i<=n; i++)
+                            {
+                                v = 0.0;
+                                for(i_=i; i_<=n;i_++)
+                                {
+                                    v += lu[i,i_]*cwork1[i_];
+                                }
+                                cwork1[i] = v;
+                            }
+                            
+                            //
+                            // Multiply by L
+                            //
+                            for(i=n; i>=1; i--)
+                            {
+                                v = 0;
+                                if( i>1 )
+                                {
+                                    v = 0.0;
+                                    for(i_=1; i_<=i-1;i_++)
+                                    {
+                                        v += lu[i,i_]*cwork1[i_];
+                                    }
+                                }
+                                cwork1[i] = v+cwork1[i];
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // Multiply by L'
+                            //
+                            for(i=1; i<=n; i++)
+                            {
+                                cwork2[i] = 0;
+                            }
+                            for(i=1; i<=n; i++)
+                            {
+                                v = cwork1[i];
+                                if( i>1 )
+                                {
+                                    for(i_=1; i_<=i-1;i_++)
+                                    {
+                                        cwork2[i_] = cwork2[i_] + v*AP.Math.Conj(lu[i,i_]);
+                                    }
+                                }
+                                cwork2[i] = cwork2[i]+v;
+                            }
+                            
+                            //
+                            // Multiply by U'
+                            //
+                            for(i=1; i<=n; i++)
+                            {
+                                cwork1[i] = 0;
+                            }
+                            for(i=1; i<=n; i++)
+                            {
+                                v = cwork2[i];
+                                for(i_=i; i_<=n;i_++)
+                                {
+                                    cwork1[i_] = cwork1[i_] + v*AP.Math.Conj(lu[i,i_]);
+                                }
+                            }
+                        }
+                    }
+                }
+                while( kase!=0 );
+            }
+            
+            //
+            // Quick return if possible
+            //
+            if( (double)(anorm)==(double)(0) )
+            {
+                return;
+            }
+            
+            //
+            // Estimate the norm of inv(A).
+            //
+            ainvnm = 0;
+            if( onenorm )
+            {
+                kase1 = 1;
+            }
+            else
+            {
+                kase1 = 2;
+            }
+            kase = 0;
+            do
+            {
+                internalcomplexrcondestimatenorm(n, ref cwork4, ref cwork1, ref ainvnm, ref kase, ref isave, ref rsave);
+                if( kase!=0 )
+                {
+                    if( kase==kase1 )
+                    {
+                        
+                        //
+                        // Multiply by inv(L).
+                        //
+                        cw = ctrlinsolve.complexsafesolvetriangular(ref lu, n, ref cwork1, false, 0, true, ref cwork2, ref cwork3);
+                        if( !cw )
+                        {
+                            rcond = 0;
+                            return;
+                        }
+                        
+                        //
+                        // Multiply by inv(U).
+                        //
+                        cw = ctrlinsolve.complexsafesolvetriangular(ref lu, n, ref cwork1, true, 0, false, ref cwork2, ref cwork3);
+                        if( !cw )
+                        {
+                            rcond = 0;
+                            return;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Multiply by inv(U').
+                        //
+                        cw = ctrlinsolve.complexsafesolvetriangular(ref lu, n, ref cwork1, true, 2, false, ref cwork2, ref cwork3);
+                        if( !cw )
+                        {
+                            rcond = 0;
+                            return;
+                        }
+                        
+                        //
+                        // Multiply by inv(L').
+                        //
+                        cw = ctrlinsolve.complexsafesolvetriangular(ref lu, n, ref cwork1, false, 2, true, ref cwork2, ref cwork3);
+                        if( !cw )
+                        {
+                            rcond = 0;
+                            return;
+                        }
+                    }
+                }
+            }
+            while( kase!=0 );
+            
+            //
+            // Compute the estimate of the reciprocal condition number.
+            //
+            if( (double)(ainvnm)!=(double)(0) )
+            {
+                rcond = 1/ainvnm;
+                rcond = rcond/anorm;
+            }
+        }
+
+
+        private static void internalcomplexrcondestimatenorm(int n,
+            ref AP.Complex[] v,
+            ref AP.Complex[] x,
+            ref double est,
+            ref int kase,
+            ref int[] isave,
+            ref double[] rsave)
+        {
+            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 = AP.Math.MinRealNumber;
+            if( kase==0 )
+            {
+                for(i=1; i<=n; i++)
+                {
+                    x[i] = (double)(1)/(double)(n);
+                }
+                kase = 1;
+                jump = 1;
+                internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                return;
+            }
+            internalcomplexrcondloadall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+            
+            //
+            // ENTRY   (JUMP = 1)
+            // FIRST ITERATION.  X HAS BEEN OVERWRITTEN BY A*X.
+            //
+            if( jump==1 )
+            {
+                if( n==1 )
+                {
+                    v[1] = x[1];
+                    est = AP.Math.AbsComplex(v[1]);
+                    kase = 0;
+                    internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                    return;
+                }
+                est = internalcomplexrcondscsum1(ref x, n);
+                for(i=1; i<=n; i++)
+                {
+                    absxi = AP.Math.AbsComplex(x[i]);
+                    if( (double)(absxi)>(double)(safmin) )
+                    {
+                        x[i] = x[i]/absxi;
+                    }
+                    else
+                    {
+                        x[i] = 1;
+                    }
+                }
+                kase = 2;
+                jump = 2;
+                internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                return;
+            }
+            
+            //
+            // ENTRY   (JUMP = 2)
+            // FIRST ITERATION.  X HAS BEEN OVERWRITTEN BY CTRANS(A)*X.
+            //
+            if( jump==2 )
+            {
+                j = internalcomplexrcondicmax1(ref 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;
+                internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                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;
+                est = internalcomplexrcondscsum1(ref v, n);
+                
+                //
+                // TEST FOR CYCLING.
+                //
+                if( (double)(est)<=(double)(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;
+                    internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                    return;
+                }
+                for(i=1; i<=n; i++)
+                {
+                    absxi = AP.Math.AbsComplex(x[i]);
+                    if( (double)(absxi)>(double)(safmin) )
+                    {
+                        x[i] = x[i]/absxi;
+                    }
+                    else
+                    {
+                        x[i] = 1;
+                    }
+                }
+                kase = 2;
+                jump = 4;
+                internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                return;
+            }
+            
+            //
+            // ENTRY   (JUMP = 4)
+            // X HAS BEEN OVERWRITTEN BY CTRANS(A)*X.
+            //
+            if( jump==4 )
+            {
+                jlast = j;
+                j = internalcomplexrcondicmax1(ref x, n);
+                if( (double)(AP.Math.AbsComplex(x[jlast]))!=(double)(AP.Math.AbsComplex(x[j])) & iter<itmax )
+                {
+                    iter = iter+1;
+                    
+                    //
+                    // MAIN LOOP - ITERATIONS 2,3,...,ITMAX.
+                    //
+                    for(i=1; i<=n; i++)
+                    {
+                        x[i] = 0;
+                    }
+                    x[j] = 1;
+                    kase = 1;
+                    jump = 3;
+                    internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                    return;
+                }
+                
+                //
+                // 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;
+                internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                return;
+            }
+            
+            //
+            // ENTRY   (JUMP = 5)
+            // X HAS BEEN OVERWRITTEN BY A*X.
+            //
+            if( jump==5 )
+            {
+                temp = 2*(internalcomplexrcondscsum1(ref x, n)/(3*n));
+                if( (double)(temp)>(double)(est) )
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        v[i_] = x[i_];
+                    }
+                    est = temp;
+                }
+                kase = 0;
+                internalcomplexrcondsaveall(ref isave, ref rsave, ref i, ref iter, ref j, ref jlast, ref jump, ref absxi, ref altsgn, ref estold, ref temp);
+                return;
+            }
+        }
+
+
+        private static double internalcomplexrcondscsum1(ref AP.Complex[] x,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+
+            result = 0;
+            for(i=1; i<=n; i++)
+            {
+                result = result+AP.Math.AbsComplex(x[i]);
+            }
+            return result;
+        }
+
+
+        private static int internalcomplexrcondicmax1(ref AP.Complex[] x,
+            int n)
+        {
+            int result = 0;
+            int i = 0;
+            double m = 0;
+
+            result = 1;
+            m = AP.Math.AbsComplex(x[1]);
+            for(i=2; i<=n; i++)
+            {
+                if( (double)(AP.Math.AbsComplex(x[i]))>(double)(m) )
+                {
+                    result = i;
+                    m = AP.Math.AbsComplex(x[i]);
+                }
+            }
+            return result;
+        }
+
+
+        private static void internalcomplexrcondsaveall(ref int[] isave,
+            ref double[] rsave,
+            ref int i,
+            ref int iter,
+            ref int j,
+            ref int jlast,
+            ref int jump,
+            ref double absxi,
+            ref double altsgn,
+            ref double estold,
+            ref double temp)
+        {
+            isave[0] = i;
+            isave[1] = iter;
+            isave[2] = j;
+            isave[3] = jlast;
+            isave[4] = jump;
+            rsave[0] = absxi;
+            rsave[1] = altsgn;
+            rsave[2] = estold;
+            rsave[3] = temp;
+        }
+
+
+        private static void internalcomplexrcondloadall(ref int[] isave,
+            ref double[] rsave,
+            ref int i,
+            ref int iter,
+            ref int j,
+            ref int jlast,
+            ref int jump,
+            ref double absxi,
+            ref double altsgn,
+            ref double estold,
+            ref double temp)
+        {
+            i = isave[0];
+            iter = isave[1];
+            j = isave[2];
+            jlast = isave[3];
+            jump = isave[4];
+            absxi = rsave[0];
+            altsgn = rsave[1];
+            estold = rsave[2];
+            temp = rsave[3];
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/creflections.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/creflections.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/creflections.cs	(revision 2645)
@@ -0,0 +1,300 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class creflections
+    {
+        /*************************************************************************
+        Generation of an elementary complex reflection transformation
+
+        The subroutine generates elementary complex reflection H of  order  N,  so
+        that, for a given X, the following equality holds true:
+
+             ( X(1) )   ( Beta )
+        H' * (  ..  ) = (  0   ),   H'*H = I,   Beta is a real number
+             ( X(n) )   (  0   )
+
+        where
+
+                      ( V(1) )
+        H = 1 - Tau * (  ..  ) * ( conj(V(1)), ..., conj(V(n)) )
+                      ( V(n) )
+
+        where the first component of vector V equals 1.
+
+        Input parameters:
+            X   -   vector. Array with elements [1..N].
+            N   -   reflection order.
+
+        Output parameters:
+            X   -   components from 2 to N are replaced by vector V.
+                    The first component is replaced with parameter Beta.
+            Tau -   scalar value Tau.
+
+        This subroutine is the modification of CLARFG subroutines  from the LAPACK
+        library. It has similar functionality except for the fact that it  doesnt
+        handle errors when intermediate results cause an overflow.
+
+          -- LAPACK auxiliary routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             September 30, 1994
+        *************************************************************************/
+        public static void complexgeneratereflection(ref AP.Complex[] x,
+            int n,
+            ref AP.Complex tau)
+        {
+            int j = 0;
+            int knt = 0;
+            AP.Complex alpha = 0;
+            double alphi = 0;
+            double alphr = 0;
+            double beta = 0;
+            double xnorm = 0;
+            double mx = 0;
+            AP.Complex t = 0;
+            int i_ = 0;
+
+            if( n<=0 )
+            {
+                tau = 0;
+                return;
+            }
+            alpha = x[1];
+            mx = 0;
+            for(j=2; j<=n; j++)
+            {
+                mx = Math.Max(AP.Math.AbsComplex(x[j]), mx);
+            }
+            xnorm = 0;
+            if( (double)(mx)!=(double)(0) )
+            {
+                for(j=2; j<=n; j++)
+                {
+                    t = x[j]/mx;
+                    xnorm = xnorm+(t*AP.Math.Conj(t)).x;
+                }
+                xnorm = Math.Sqrt(xnorm)*mx;
+            }
+            alphr = alpha.x;
+            alphi = alpha.y;
+            if( (double)(xnorm)==(double)(0) & (double)(alphi)==(double)(0) )
+            {
+                tau = 0;
+                return;
+            }
+            mx = Math.Max(Math.Abs(alphr), Math.Abs(alphi));
+            mx = Math.Max(mx, Math.Abs(xnorm));
+            beta = -(mx*Math.Sqrt(AP.Math.Sqr(alphr/mx)+AP.Math.Sqr(alphi/mx)+AP.Math.Sqr(xnorm/mx)));
+            if( (double)(alphr)<(double)(0) )
+            {
+                beta = -beta;
+            }
+            tau.x = (beta-alphr)/beta;
+            tau.y = -(alphi/beta);
+            alpha = 1/(alpha-beta);
+            if( n>1 )
+            {
+                for(i_=2; i_<=n;i_++)
+                {
+                    x[i_] = alpha*x[i_];
+                }
+            }
+            alpha = beta;
+            x[1] = alpha;
+        }
+
+
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static void complexapplyreflectionfromtheleft(ref AP.Complex[,] c,
+            AP.Complex tau,
+            ref AP.Complex[] v,
+            int m1,
+            int m2,
+            int n1,
+            int n2,
+            ref AP.Complex[] work)
+        {
+            AP.Complex t = 0;
+            int i = 0;
+            int vm = 0;
+            int i_ = 0;
+
+            if( tau==0 | n1>n2 | m1>m2 )
+            {
+                return;
+            }
+            
+            //
+            // 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 = AP.Math.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,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
+        *************************************************************************/
+        public static void complexapplyreflectionfromtheright(ref AP.Complex[,] c,
+            AP.Complex tau,
+            ref AP.Complex[] v,
+            int m1,
+            int m2,
+            int n1,
+            int n2,
+            ref AP.Complex[] work)
+        {
+            AP.Complex t = 0;
+            int i = 0;
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( tau==0 | n1>n2 | m1>m2 )
+            {
+                return;
+            }
+            
+            //
+            // w := C * v
+            //
+            vm = n2-n1+1;
+            for(i=m1; i<=m2; i++)
+            {
+                i1_ = (1)-(n1);
+                t = 0.0;
+                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_] = AP.Math.Conj(v[i_]);
+            }
+            for(i=m1; i<=m2; i++)
+            {
+                t = work[i]*tau;
+                i1_ = (1) - (n1);
+                for(i_=n1; i_<=n2;i_++)
+                {
+                    c[i,i_] = c[i,i_] - t*v[i_+i1_];
+                }
+            }
+            for(i_=1; i_<=vm;i_++)
+            {
+                v[i_] = AP.Math.Conj(v[i_]);
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/csolve.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/csolve.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/csolve.cs	(revision 2645)
@@ -0,0 +1,262 @@
+/*************************************************************************
+This file is a part of ALGLIB project.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class csolve
+    {
+        /*************************************************************************
+        Solving a system of linear equations with a system matrix given by its
+        LU decomposition.
+
+        The algorithm solves a system of linear equations whose matrix is given by
+        its LU decomposition. In case of a singular matrix, the algorithm  returns
+        False.
+
+        The algorithm solves systems with a square matrix only.
+
+        Input parameters:
+            A       -   LU decomposition of a system matrix in compact  form  (the
+                        result of the RMatrixLU subroutine).
+            Pivots  -   row permutation table (the result of a
+                        RMatrixLU subroutine).
+            B       -   right side of a system.
+                        Array whose index ranges within [0..N-1].
+            N       -   size of matrix A.
+
+        Output parameters:
+            X       -   solution of a system.
+                        Array whose index ranges within [0..N-1].
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrux is singular. In this case, X doesn't contain a
+        solution.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool cmatrixlusolve(ref AP.Complex[,] a,
+            ref int[] pivots,
+            AP.Complex[] b,
+            int n,
+            ref AP.Complex[] x)
+        {
+            bool result = new bool();
+            AP.Complex[] y = new AP.Complex[0];
+            int i = 0;
+            int j = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+
+            b = (AP.Complex[])b.Clone();
+
+            y = new AP.Complex[n-1+1];
+            x = new AP.Complex[n-1+1];
+            result = true;
+            for(i=0; i<=n-1; i++)
+            {
+                if( a[i,i]==0 )
+                {
+                    result = false;
+                    return result;
+                }
+            }
+            
+            //
+            // pivots
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                if( pivots[i]!=i )
+                {
+                    v = b[i];
+                    b[i] = b[pivots[i]];
+                    b[pivots[i]] = v;
+                }
+            }
+            
+            //
+            // Ly = b
+            //
+            y[0] = b[0];
+            for(i=1; i<=n-1; i++)
+            {
+                v = 0.0;
+                for(i_=0; i_<=i-1;i_++)
+                {
+                    v += a[i,i_]*y[i_];
+                }
+                y[i] = b[i]-v;
+            }
+            
+            //
+            // Ux = y
+            //
+            x[n-1] = y[n-1]/a[n-1,n-1];
+            for(i=n-2; i>=0; i--)
+            {
+                v = 0.0;
+                for(i_=i+1; i_<=n-1;i_++)
+                {
+                    v += a[i,i_]*x[i_];
+                }
+                x[i] = (y[i]-v)/a[i,i];
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Solving a system of linear equations.
+
+        The algorithm solves a system of linear equations by using the
+        LU decomposition. The algorithm solves systems with a square matrix only.
+
+        Input parameters:
+            A   -   system matrix.
+                    Array whose indexes range within [0..N-1, 0..N-1].
+            B   -   right side of a system.
+                    Array whose indexes range within [0..N-1].
+            N   -   size of matrix A.
+
+        Output parameters:
+            X   -   solution of a system.
+                    Array whose index ranges within [0..N-1].
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular. In this case, X doesn't contain a
+        solution.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool cmatrixsolve(AP.Complex[,] a,
+            AP.Complex[] b,
+            int n,
+            ref AP.Complex[] x)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+            int i = 0;
+
+            a = (AP.Complex[,])a.Clone();
+            b = (AP.Complex[])b.Clone();
+
+            clu.cmatrixlu(ref a, n, n, ref pivots);
+            result = cmatrixlusolve(ref a, ref pivots, b, n, ref x);
+            return result;
+        }
+
+
+        public static bool complexsolvesystemlu(ref AP.Complex[,] a,
+            ref int[] pivots,
+            AP.Complex[] b,
+            int n,
+            ref AP.Complex[] x)
+        {
+            bool result = new bool();
+            AP.Complex[] y = new AP.Complex[0];
+            int i = 0;
+            AP.Complex v = 0;
+            int ip1 = 0;
+            int im1 = 0;
+            int i_ = 0;
+
+            b = (AP.Complex[])b.Clone();
+
+            y = new AP.Complex[n+1];
+            x = new AP.Complex[n+1];
+            result = true;
+            for(i=1; i<=n; i++)
+            {
+                if( a[i,i]==0 )
+                {
+                    result = false;
+                    return result;
+                }
+            }
+            
+            //
+            // pivots
+            //
+            for(i=1; i<=n; i++)
+            {
+                if( pivots[i]!=i )
+                {
+                    v = b[i];
+                    b[i] = b[pivots[i]];
+                    b[pivots[i]] = v;
+                }
+            }
+            
+            //
+            // Ly = b
+            //
+            y[1] = b[1];
+            for(i=2; i<=n; i++)
+            {
+                im1 = i-1;
+                v = 0.0;
+                for(i_=1; i_<=im1;i_++)
+                {
+                    v += a[i,i_]*y[i_];
+                }
+                y[i] = b[i]-v;
+            }
+            
+            //
+            // Ux = y
+            //
+            x[n] = y[n]/a[n,n];
+            for(i=n-1; i>=1; i--)
+            {
+                ip1 = i+1;
+                v = 0.0;
+                for(i_=ip1; i_<=n;i_++)
+                {
+                    v += a[i,i_]*x[i_];
+                }
+                x[i] = (y[i]-v)/a[i,i];
+            }
+            return result;
+        }
+
+
+        public static bool complexsolvesystem(AP.Complex[,] a,
+            AP.Complex[] b,
+            int n,
+            ref AP.Complex[] x)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            a = (AP.Complex[,])a.Clone();
+            b = (AP.Complex[])b.Clone();
+
+            clu.complexludecomposition(ref a, n, n, ref pivots);
+            result = complexsolvesystemlu(ref a, ref pivots, b, n, ref x);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ctrinverse.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ctrinverse.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ctrinverse.cs	(revision 2645)
@@ -0,0 +1,374 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ctrinverse
+    {
+        /*************************************************************************
+        Complex triangular matrix inversion
+
+        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, the diagonal elements are not passed to the algorithm, they  are
+        not changed by the algorithm.
+
+        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.
+            IsunitTriangular
+                    -   True, if the matrix has a unit diagonal.
+
+        Output parameters:
+            A       -   inverse matrix (if the problem is not degenerate).
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular.
+
+          -- 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
+        *************************************************************************/
+        public static bool cmatrixtrinverse(ref AP.Complex[,] a,
+            int n,
+            bool isupper,
+            bool isunittriangular)
+        {
+            bool result = new bool();
+            bool nounit = new bool();
+            int i = 0;
+            int j = 0;
+            AP.Complex v = 0;
+            AP.Complex ajj = 0;
+            AP.Complex[] t = new AP.Complex[0];
+            int i_ = 0;
+
+            result = true;
+            t = new AP.Complex[n-1+1];
+            
+            //
+            // Test the input parameters.
+            //
+            nounit = !isunittriangular;
+            if( isupper )
+            {
+                
+                //
+                // Compute inverse of upper triangular matrix.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    if( nounit )
+                    {
+                        if( a[j,j]==0 )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    
+                    //
+                    // Compute elements 1:j-1 of j-th column.
+                    //
+                    if( j>0 )
+                    {
+                        for(i_=0; i_<=j-1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=0; i<=j-1; i++)
+                        {
+                            if( i+1<j )
+                            {
+                                v = 0.0;
+                                for(i_=i+1; i_<=j-1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=0; i_<=j-1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inverse of lower triangular matrix.
+                //
+                for(j=n-1; j>=0; j--)
+                {
+                    if( nounit )
+                    {
+                        if( a[j,j]==0 )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    if( j+1<n )
+                    {
+                        
+                        //
+                        // Compute elements j+1:n of j-th column.
+                        //
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=j+1; i<=n-1; i++)
+                        {
+                            if( i>j+1 )
+                            {
+                                v = 0.0;
+                                for(i_=j+1; i_<=i-1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool complexinvtriangular(ref AP.Complex[,] a,
+            int n,
+            bool isupper,
+            bool isunittriangular)
+        {
+            bool result = new bool();
+            bool nounit = new bool();
+            int i = 0;
+            int j = 0;
+            int nmj = 0;
+            int jm1 = 0;
+            int jp1 = 0;
+            AP.Complex v = 0;
+            AP.Complex ajj = 0;
+            AP.Complex[] t = new AP.Complex[0];
+            int i_ = 0;
+
+            result = true;
+            t = new AP.Complex[n+1];
+            
+            //
+            // Test the input parameters.
+            //
+            nounit = !isunittriangular;
+            if( isupper )
+            {
+                
+                //
+                // Compute inverse of upper triangular matrix.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    if( nounit )
+                    {
+                        if( a[j,j]==0 )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    
+                    //
+                    // Compute elements 1:j-1 of j-th column.
+                    //
+                    if( j>1 )
+                    {
+                        jm1 = j-1;
+                        for(i_=1; i_<=jm1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=1; i<=j-1; i++)
+                        {
+                            if( i<j-1 )
+                            {
+                                v = 0.0;
+                                for(i_=i+1; i_<=jm1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=1; i_<=jm1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inverse of lower triangular matrix.
+                //
+                for(j=n; j>=1; j--)
+                {
+                    if( nounit )
+                    {
+                        if( a[j,j]==0 )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    if( j<n )
+                    {
+                        
+                        //
+                        // Compute elements j+1:n of j-th column.
+                        //
+                        nmj = n-j;
+                        jp1 = j+1;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=j+1; i<=n; i++)
+                        {
+                            if( i>j+1 )
+                            {
+                                v = 0.0;
+                                for(i_=jp1; i_<=i-1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ctrlinsolve.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ctrlinsolve.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ctrlinsolve.cs	(revision 2645)
@@ -0,0 +1,318 @@
+/*************************************************************************
+This file is a part of ALGLIB project.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ctrlinsolve
+    {
+        /*************************************************************************
+        Utility subroutine performing the "safe" solution of a  system  of  linear
+        equations with triangular complex coefficient matrices.
+
+        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. If an overflow
+        is possible, an error code is returned.
+
+        The algorithm can solve systems of equations with upper/lower triangular
+        matrices,  with/without unit diagonal, and systems of types A*x=b, A^T*x=b,
+        A^H*x=b.
+
+        Input parameters:
+            A       -   system matrix.
+                        Array whose indexes range within [1..N, 1..N].
+            N       -   size of matrix A.
+            X       -   right-hand member of a system.
+                        Array whose index ranges within [1..N].
+            IsUpper -   matrix type. If it is True, the system matrix is the upper
+                        triangular matrix and is located in the corresponding part
+                        of matrix A.
+            Trans   -   problem type.
+                        If Trans is:
+                            * 0, A*x=b
+                            * 1, A^T*x=b
+                            * 2, A^H*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.
+            CNORM   -   array which is stored in norms of rows and columns of  the
+                        matrix. If the array hasn't been filled up during previous
+                        executions  of  an  algorithm  with the same matrix as the
+                        input,  it  will  be  filled  up by the subroutine. If the
+                        array is filled up, the subroutine uses it without filling
+                        it up again.
+            NORMIN  -   flag defining the state of column norms array. If True, the
+                        array is filled up.
+            WORKA   -   working array whose index ranges within [1..N].
+            WORKX   -   working array whose index ranges within [1..N].
+
+        Output parameters (if the result is True):
+            X       -   solution. Array whose index ranges within [1..N].
+            CNORM   -   array of column norms whose index ranges within [1..N].
+
+        Result:
+            True, if the matrix is not singular  and  the  algorithm  finished its
+                work correctly without causing an overflow.
+            False, if  the  matrix  is  singular  or  the  algorithm was cancelled
+                because of an overflow possibility.
+
+        Note:
+            The disadvantage of an algorithm is that  sometimes  it  overestimates
+            an overflow probability. This is not a problem when  solving  ordinary
+            systems. If the elements of the matrix used as the input are close  to
+            MaxRealNumber, a false overflow detection is possible, but in practice
+            such matrices can rarely be found.
+            You can find more reliable subroutines in the LAPACK library
+            (xLATRS subroutine ).
+
+          -- ALGLIB --
+             Copyright 31.03.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool complexsafesolvetriangular(ref AP.Complex[,] a,
+            int n,
+            ref AP.Complex[] x,
+            bool isupper,
+            int trans,
+            bool isunit,
+            ref AP.Complex[] worka,
+            ref AP.Complex[] workx)
+        {
+            bool result = new bool();
+            int i = 0;
+            int l = 0;
+            int j = 0;
+            bool dolswp = new bool();
+            double ma = 0;
+            double mx = 0;
+            double v = 0;
+            AP.Complex t = 0;
+            AP.Complex r = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(trans>=0 & trans<=2, "ComplexSafeSolveTriangular: incorrect parameters!");
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n<=0 )
+            {
+                return result;
+            }
+            
+            //
+            // Main cycle
+            //
+            for(l=1; l<=n; l++)
+            {
+                
+                //
+                // Prepare subtask L
+                //
+                dolswp = false;
+                if( trans==0 )
+                {
+                    if( isupper )
+                    {
+                        i = n+1-l;
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            worka[i_] = a[i,i_+i1_];
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            workx[i_] = x[i_+i1_];
+                        }
+                        dolswp = true;
+                    }
+                    if( !isupper )
+                    {
+                        i = l;
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            worka[i_] = a[i,i_];
+                        }
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            workx[i_] = x[i_];
+                        }
+                    }
+                }
+                if( trans==1 )
+                {
+                    if( isupper )
+                    {
+                        i = l;
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            worka[i_] = a[i_,i];
+                        }
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            workx[i_] = x[i_];
+                        }
+                    }
+                    if( !isupper )
+                    {
+                        i = n+1-l;
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            worka[i_] = a[i_+i1_,i];
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            workx[i_] = x[i_+i1_];
+                        }
+                        dolswp = true;
+                    }
+                }
+                if( trans==2 )
+                {
+                    if( isupper )
+                    {
+                        i = l;
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            worka[i_] = AP.Math.Conj(a[i_,i]);
+                        }
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            workx[i_] = x[i_];
+                        }
+                    }
+                    if( !isupper )
+                    {
+                        i = n+1-l;
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            worka[i_] = AP.Math.Conj(a[i_+i1_,i]);
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            workx[i_] = x[i_+i1_];
+                        }
+                        dolswp = true;
+                    }
+                }
+                if( dolswp )
+                {
+                    t = workx[l];
+                    workx[l] = workx[1];
+                    workx[1] = t;
+                    t = worka[l];
+                    worka[l] = worka[1];
+                    worka[1] = t;
+                }
+                if( isunit )
+                {
+                    worka[l] = 1;
+                }
+                
+                //
+                // Test if workA[L]=0
+                //
+                if( worka[l]==0 )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Now we have:
+                //
+                //  workA[1:L]*workX[1:L] = b[I]
+                //
+                // with known workA[1:L] and workX[1:L-1]
+                // and unknown workX[L]
+                //
+                t = 0;
+                if( l>=2 )
+                {
+                    ma = 0;
+                    for(j=1; j<=l-1; j++)
+                    {
+                        ma = Math.Max(ma, AP.Math.AbsComplex(worka[j]));
+                    }
+                    mx = 0;
+                    for(j=1; j<=l-1; j++)
+                    {
+                        mx = Math.Max(mx, AP.Math.AbsComplex(workx[j]));
+                    }
+                    if( (double)(Math.Max(ma, mx))>(double)(1) )
+                    {
+                        v = AP.Math.MaxRealNumber/Math.Max(ma, mx);
+                        v = v/(l-1);
+                        if( (double)(v)<(double)(Math.Min(ma, mx)) )
+                        {
+                            result = false;
+                            return result;
+                        }
+                    }
+                    t = 0.0;
+                    for(i_=1; i_<=l-1;i_++)
+                    {
+                        t += worka[i_]*workx[i_];
+                    }
+                }
+                
+                //
+                // Now we have:
+                //
+                //  workA[L]*workX[L] + T = b[I]
+                //
+                if( (double)(Math.Max(AP.Math.AbsComplex(t), AP.Math.AbsComplex(x[i])))>=(double)(0.5*AP.Math.MaxRealNumber) )
+                {
+                    result = false;
+                    return result;
+                }
+                r = x[i]-t;
+                
+                //
+                // Now we have:
+                //
+                //  workA[L]*workX[L] = R
+                //
+                if( r!=0 )
+                {
+                    if( (double)(Math.Log(AP.Math.AbsComplex(r))-Math.Log(AP.Math.AbsComplex(worka[l])))>=(double)(Math.Log(AP.Math.MaxRealNumber)) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                }
+                
+                //
+                // X[I]
+                //
+                x[i] = r/worka[l];
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/dawson.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/dawson.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/dawson.cs	(revision 2645)
@@ -0,0 +1,156 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class dawson
+    {
+        /*************************************************************************
+        Dawson's Integral
+
+        Approximates the integral
+
+                                    x
+                                    -
+                             2     | |        2
+         dawsn(x)  =  exp( -x  )   |    exp( t  ) dt
+                                 | |
+                                  -
+                                  0
+
+        Three different rational approximations are employed, for
+        the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,10        10000       6.9e-16     1.0e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double dawsonintegral(double x)
+        {
+            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;
+
+            sg = 1;
+            if( (double)(x)<(double)(0) )
+            {
+                sg = -1;
+                x = -x;
+            }
+            if( (double)(x)<(double)(3.25) )
+            {
+                x2 = x*x;
+                an = 1.13681498971755972054E-11;
+                an = an*x2+8.49262267667473811108E-10;
+                an = an*x2+1.94434204175553054283E-8;
+                an = an*x2+9.53151741254484363489E-7;
+                an = an*x2+3.07828309874913200438E-6;
+                an = an*x2+3.52513368520288738649E-4;
+                an = an*x2+-8.50149846724410912031E-4;
+                an = an*x2+4.22618223005546594270E-2;
+                an = an*x2+-9.17480371773452345351E-2;
+                an = an*x2+9.99999999999999994612E-1;
+                ad = 2.40372073066762605484E-11;
+                ad = ad*x2+1.48864681368493396752E-9;
+                ad = ad*x2+5.21265281010541664570E-8;
+                ad = ad*x2+1.27258478273186970203E-6;
+                ad = ad*x2+2.32490249820789513991E-5;
+                ad = ad*x2+3.25524741826057911661E-4;
+                ad = ad*x2+3.48805814657162590916E-3;
+                ad = ad*x2+2.79448531198828973716E-2;
+                ad = ad*x2+1.58874241960120565368E-1;
+                ad = ad*x2+5.74918629489320327824E-1;
+                ad = ad*x2+1.00000000000000000539E0;
+                y = x*an/ad;
+                result = sg*y;
+                return result;
+            }
+            x2 = 1.0/(x*x);
+            if( (double)(x)<(double)(6.25) )
+            {
+                bn = 5.08955156417900903354E-1;
+                bn = bn*x2-2.44754418142697847934E-1;
+                bn = bn*x2+9.41512335303534411857E-2;
+                bn = bn*x2-2.18711255142039025206E-2;
+                bn = bn*x2+3.66207612329569181322E-3;
+                bn = bn*x2-4.23209114460388756528E-4;
+                bn = bn*x2+3.59641304793896631888E-5;
+                bn = bn*x2-2.14640351719968974225E-6;
+                bn = bn*x2+9.10010780076391431042E-8;
+                bn = bn*x2-2.40274520828250956942E-9;
+                bn = bn*x2+3.59233385440928410398E-11;
+                bd = 1.00000000000000000000E0;
+                bd = bd*x2-6.31839869873368190192E-1;
+                bd = bd*x2+2.36706788228248691528E-1;
+                bd = bd*x2-5.31806367003223277662E-2;
+                bd = bd*x2+8.48041718586295374409E-3;
+                bd = bd*x2-9.47996768486665330168E-4;
+                bd = bd*x2+7.81025592944552338085E-5;
+                bd = bd*x2-4.55875153252442634831E-6;
+                bd = bd*x2+1.89100358111421846170E-7;
+                bd = bd*x2-4.91324691331920606875E-9;
+                bd = bd*x2+7.18466403235734541950E-11;
+                y = 1.0/x+x2*bn/(bd*x);
+                result = sg*0.5*y;
+                return result;
+            }
+            if( (double)(x)>(double)(1.0E9) )
+            {
+                result = sg*0.5/x;
+                return result;
+            }
+            cn = -5.90592860534773254987E-1;
+            cn = cn*x2+6.29235242724368800674E-1;
+            cn = cn*x2-1.72858975380388136411E-1;
+            cn = cn*x2+1.64837047825189632310E-2;
+            cn = cn*x2-4.86827613020462700845E-4;
+            cd = 1.00000000000000000000E0;
+            cd = cd*x2-2.69820057197544900361E0;
+            cd = cd*x2+1.73270799045947845857E0;
+            cd = cd*x2-3.93708582281939493482E-1;
+            cd = cd*x2+3.44278924041233391079E-2;
+            cd = cd*x2-9.73655226040941223894E-4;
+            y = 1.0/x+x2*cn/(cd*x);
+            result = sg*0.5*y;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/densesolver.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/densesolver.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/densesolver.cs	(revision 2645)
@@ -0,0 +1,664 @@
+/*************************************************************************
+Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class densesolver
+    {
+        public struct densesolverreport
+        {
+            public double r1;
+            public double rinf;
+        };
+
+
+        public struct densesolverlsreport
+        {
+            public double r2;
+            public double[,] cx;
+            public int n;
+            public int k;
+        };
+
+
+
+
+        /*************************************************************************
+        Dense solver.
+
+        This  subroutine  solves  a  system  A*X=B,  where A is NxN non-denegerate
+        real matrix, X and B are NxM real matrices.
+
+        Additional features include:
+        * automatic detection of degenerate cases
+        * iterative improvement
+
+        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       -   size of right part
+            
+        OUTPUT PARAMETERS
+            Info    -   return code:
+                        * -3    if A is singular, or VERY close to singular.
+                                X is filled by zeros in such cases.
+                        * -1    if N<=0 or M<=0 was passed
+                        *  1    if task is solved (matrix A may be near  singular,
+                                check R1/RInf parameters for condition numbers).
+            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:
+        * R1        reciprocal of condition number: 1/cond(A), 1-norm.
+        * RInf      reciprocal of condition number: 1/cond(A), inf-norm.
+
+        SEE ALSO:
+            DenseSolverR() - solves A*x = b, where x and b are Nx1 matrices.
+
+          -- ALGLIB --
+             Copyright 24.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixsolvem(ref double[,] a,
+            int n,
+            ref double[,] b,
+            int m,
+            ref int info,
+            ref densesolverreport rep,
+            ref double[,] x)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int rfs = 0;
+            int nrfs = 0;
+            int[] p = new int[0];
+            double[] xc = new double[0];
+            double[] y = new double[0];
+            double[] bc = new double[0];
+            double[] xa = new double[0];
+            double[] xb = new double[0];
+            double[] tx = new double[0];
+            double[,] da = new double[0,0];
+            double v = 0;
+            double verr = 0;
+            bool smallerr = new bool();
+            bool terminatenexttime = new bool();
+            int i_ = 0;
+
+            
+            //
+            // prepare: check inputs, allocate space...
+            //
+            if( n<=0 | m<=0 )
+            {
+                info = -1;
+                return;
+            }
+            da = new double[n, n];
+            x = new double[n, m];
+            y = new double[n];
+            xc = new double[n];
+            bc = new double[n];
+            tx = new double[n+1];
+            xa = new double[n+1];
+            xb = new double[n+1];
+            
+            //
+            // factorize matrix, test for exact/near singularity
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    da[i,i_] = a[i,i_];
+                }
+            }
+            lu.rmatrixlu(ref da, n, n, ref p);
+            rep.r1 = rcond.rmatrixlurcond1(ref da, n);
+            rep.rinf = rcond.rmatrixlurcondinf(ref da, n);
+            if( (double)(rep.r1)<(double)(10*AP.Math.MachineEpsilon) | (double)(rep.rinf)<(double)(10*AP.Math.MachineEpsilon) )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    for(j=0; j<=m-1; j++)
+                    {
+                        x[i,j] = 0;
+                    }
+                }
+                rep.r1 = 0;
+                rep.rinf = 0;
+                info = -3;
+                return;
+            }
+            info = 1;
+            
+            //
+            // solve
+            //
+            for(k=0; k<=m-1; k++)
+            {
+                
+                //
+                // First, non-iterative part of solution process:
+                // * pivots
+                // * L*y = b
+                // * U*x = y
+                //
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    bc[i_] = b[i_,k];
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    if( p[i]!=i )
+                    {
+                        v = bc[i];
+                        bc[i] = bc[p[i]];
+                        bc[p[i]] = v;
+                    }
+                }
+                y[0] = bc[0];
+                for(i=1; i<=n-1; i++)
+                {
+                    v = 0.0;
+                    for(i_=0; i_<=i-1;i_++)
+                    {
+                        v += da[i,i_]*y[i_];
+                    }
+                    y[i] = bc[i]-v;
+                }
+                xc[n-1] = y[n-1]/da[n-1,n-1];
+                for(i=n-2; i>=0; i--)
+                {
+                    v = 0.0;
+                    for(i_=i+1; i_<=n-1;i_++)
+                    {
+                        v += da[i,i_]*xc[i_];
+                    }
+                    xc[i] = (y[i]-v)/da[i,i];
+                }
+                
+                //
+                // Iterative improvement of xc:
+                // * calculate r = bc-A*xc using extra-precise dot product
+                // * solve A*y = r
+                // * update x:=x+r
+                //
+                // This cycle is executed until one of two things happens:
+                // 1. maximum number of iterations reached
+                // 2. last iteration decreased error to the lower limit
+                //
+                nrfs = densesolverrfsmax(n, rep.r1, rep.rinf);
+                terminatenexttime = false;
+                for(rfs=0; rfs<=nrfs-1; rfs++)
+                {
+                    if( terminatenexttime )
+                    {
+                        break;
+                    }
+                    
+                    //
+                    // generate right part
+                    //
+                    smallerr = true;
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            xa[i_] = a[i,i_];
+                        }
+                        xa[n] = -1;
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            xb[i_] = xc[i_];
+                        }
+                        xb[n] = b[i,k];
+                        xblas.xdot(ref xa, ref xb, n+1, ref tx, ref v, ref verr);
+                        bc[i] = -v;
+                        smallerr = smallerr & (double)(Math.Abs(v))<(double)(4*verr);
+                    }
+                    if( smallerr )
+                    {
+                        terminatenexttime = true;
+                    }
+                    
+                    //
+                    // solve
+                    //
+                    for(i=0; i<=n-1; i++)
+                    {
+                        if( p[i]!=i )
+                        {
+                            v = bc[i];
+                            bc[i] = bc[p[i]];
+                            bc[p[i]] = v;
+                        }
+                    }
+                    y[0] = bc[0];
+                    for(i=1; i<=n-1; i++)
+                    {
+                        v = 0.0;
+                        for(i_=0; i_<=i-1;i_++)
+                        {
+                            v += da[i,i_]*y[i_];
+                        }
+                        y[i] = bc[i]-v;
+                    }
+                    tx[n-1] = y[n-1]/da[n-1,n-1];
+                    for(i=n-2; i>=0; i--)
+                    {
+                        v = 0.0;
+                        for(i_=i+1; i_<=n-1;i_++)
+                        {
+                            v += da[i,i_]*tx[i_];
+                        }
+                        tx[i] = (y[i]-v)/da[i,i];
+                    }
+                    
+                    //
+                    // update
+                    //
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        xc[i_] = xc[i_] + tx[i_];
+                    }
+                }
+                
+                //
+                // Store xc
+                //
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    x[i_,k] = xc[i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        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
+
+        Additional features include:
+        * iterative improvement
+
+        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.
+
+          -- ALGLIB --
+             Copyright 24.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixsolvels(ref double[,] a,
+            int nrows,
+            int ncols,
+            ref double[] b,
+            double threshold,
+            ref int info,
+            ref densesolverlsreport rep,
+            ref double[] x)
+        {
+            double[] sv = new double[0];
+            double[,] u = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] rp = new double[0];
+            double[] utb = new double[0];
+            double[] sutb = new double[0];
+            double[] tmp = new double[0];
+            double[] ta = new double[0];
+            double[] tx = new double[0];
+            double[] buf = new double[0];
+            double[] w = new double[0];
+            int i = 0;
+            int j = 0;
+            int nsv = 0;
+            int kernelidx = 0;
+            double v = 0;
+            double verr = 0;
+            bool svdfailed = new bool();
+            bool zeroa = new bool();
+            int rfs = 0;
+            int nrfs = 0;
+            bool terminatenexttime = new bool();
+            bool smallerr = new bool();
+            int i_ = 0;
+
+            if( nrows<=0 | ncols<=0 | (double)(threshold)<(double)(0) )
+            {
+                info = -1;
+                return;
+            }
+            if( (double)(threshold)==(double)(0) )
+            {
+                threshold = 1000*AP.Math.MachineEpsilon;
+            }
+            
+            //
+            // Factorize A first
+            //
+            svdfailed = !svd.rmatrixsvd(a, nrows, ncols, 1, 2, 2, ref sv, ref u, ref vt);
+            zeroa = (double)(sv[0])==(double)(0);
+            if( svdfailed | zeroa )
+            {
+                if( svdfailed )
+                {
+                    info = -4;
+                }
+                else
+                {
+                    info = 1;
+                }
+                x = new double[ncols];
+                for(i=0; i<=ncols-1; i++)
+                {
+                    x[i] = 0;
+                }
+                rep.n = ncols;
+                rep.k = ncols;
+                rep.cx = new double[ncols, ncols];
+                for(i=0; i<=ncols-1; i++)
+                {
+                    for(j=0; j<=ncols-1; j++)
+                    {
+                        if( i==j )
+                        {
+                            rep.cx[i,j] = 1;
+                        }
+                        else
+                        {
+                            rep.cx[i,j] = 0;
+                        }
+                    }
+                }
+                rep.r2 = 0;
+                return;
+            }
+            nsv = Math.Min(ncols, nrows);
+            if( nsv==ncols )
+            {
+                rep.r2 = sv[nsv-1]/sv[0];
+            }
+            else
+            {
+                rep.r2 = 0;
+            }
+            rep.n = ncols;
+            info = 1;
+            
+            //
+            // Iterative improvement 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
+            //
+            utb = new double[nsv];
+            sutb = new double[nsv];
+            x = new double[ncols];
+            tmp = new double[ncols];
+            ta = new double[ncols+1];
+            tx = new double[ncols+1];
+            buf = new double[ncols+1];
+            for(i=0; i<=ncols-1; i++)
+            {
+                x[i] = 0;
+            }
+            kernelidx = nsv;
+            for(i=0; i<=nsv-1; i++)
+            {
+                if( (double)(sv[i])<=(double)(threshold*sv[0]) )
+                {
+                    kernelidx = i;
+                    break;
+                }
+            }
+            rep.k = ncols-kernelidx;
+            nrfs = densesolverrfsmaxv2(ncols, rep.r2);
+            terminatenexttime = false;
+            rp = new double[nrows];
+            for(rfs=0; rfs<=nrfs; rfs++)
+            {
+                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++)
+                    {
+                        for(i_=0; i_<=ncols-1;i_++)
+                        {
+                            ta[i_] = a[i,i_];
+                        }
+                        ta[ncols] = -1;
+                        for(i_=0; i_<=ncols-1;i_++)
+                        {
+                            tx[i_] = x[i_];
+                        }
+                        tx[ncols] = b[i];
+                        xblas.xdot(ref ta, ref tx, ncols+1, ref buf, ref v, ref verr);
+                        rp[i] = -v;
+                        smallerr = smallerr & (double)(Math.Abs(v))<(double)(4*verr);
+                    }
+                    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;
+                }
+                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++)
+                {
+                    if( i<kernelidx )
+                    {
+                        sutb[i] = utb[i]/sv[i];
+                    }
+                    else
+                    {
+                        sutb[i] = 0;
+                    }
+                }
+                for(i=0; i<=nsv-1; i++)
+                {
+                    v = sutb[i];
+                    for(i_=0; i_<=ncols-1;i_++)
+                    {
+                        tmp[i_] = tmp[i_] + v*vt[i,i_];
+                    }
+                }
+                
+                //
+                // update x:  x:=x+dx
+                //
+                for(i_=0; i_<=ncols-1;i_++)
+                {
+                    x[i_] = x[i_] + tmp[i_];
+                }
+            }
+            
+            //
+            // fill CX
+            //
+            if( rep.k>0 )
+            {
+                rep.cx = new double[ncols, rep.k];
+                for(i=0; i<=rep.k-1; i++)
+                {
+                    for(i_=0; i_<=ncols-1;i_++)
+                    {
+                        rep.cx[i_,i] = vt[kernelidx+i,i_];
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Dense solver.
+
+        Similar to RMatrixSolveM() but solves task with one right part  (where b/x
+        are vectors, not matrices).
+
+        See RMatrixSolveM()  description  for  more  information  about subroutine
+        parameters.
+
+          -- ALGLIB --
+             Copyright 24.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixsolve(ref double[,] a,
+            int n,
+            ref double[] b,
+            ref int info,
+            ref densesolverreport rep,
+            ref double[] x)
+        {
+            double[,] bm = new double[0,0];
+            double[,] xm = new double[0,0];
+            int i_ = 0;
+
+            if( n<=0 )
+            {
+                info = -1;
+                return;
+            }
+            bm = new double[n, 1];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                bm[i_,0] = b[i_];
+            }
+            rmatrixsolvem(ref a, n, ref bm, 1, ref info, ref rep, ref xm);
+            x = new double[n];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                x[i_] = xm[i_,0];
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine.
+        Returns maximum count of RFS iterations as function of:
+        1. machine epsilon
+        2. task size.
+        3. condition number
+        *************************************************************************/
+        private static int densesolverrfsmax(int n,
+            double r1,
+            double rinf)
+        {
+            int result = 0;
+
+            result = 2;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine.
+        Returns maximum count of RFS iterations as function of:
+        1. machine epsilon
+        2. task size.
+        3. norm-2 condition number
+        *************************************************************************/
+        private static int densesolverrfsmaxv2(int n,
+            double r2)
+        {
+            int result = 0;
+
+            result = densesolverrfsmax(n, 0, 0);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/descriptivestatistics.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/descriptivestatistics.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/descriptivestatistics.cs	(revision 2645)
@@ -0,0 +1,436 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class descriptivestatistics
+    {
+        /*************************************************************************
+        Calculation of the distribution moments: mean, variance, slewness, kurtosis.
+
+        Input parameters:
+            X       -   sample. Array with whose indexes range within [0..N-1]
+            N       -   sample size.
+            
+        Output parameters:
+            Mean    -   mean.
+            Variance-   variance.
+            Skewness-   skewness (if variance<>0; zero otherwise).
+            Kurtosis-   kurtosis (if variance<>0; zero otherwise).
+
+          -- ALGLIB --
+             Copyright 06.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void calculatemoments(ref double[] x,
+            int n,
+            ref double mean,
+            ref double variance,
+            ref double skewness,
+            ref double kurtosis)
+        {
+            int i = 0;
+            double v = 0;
+            double v1 = 0;
+            double v2 = 0;
+            double stddev = 0;
+
+            mean = 0;
+            variance = 0;
+            skewness = 0;
+            kurtosis = 0;
+            stddev = 0;
+            if( n<=0 )
+            {
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                mean = mean+x[i];
+            }
+            mean = mean/n;
+            
+            //
+            // Variance (using corrected two-pass algorithm)
+            //
+            if( n!=1 )
+            {
+                v1 = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v1 = v1+AP.Math.Sqr(x[i]-mean);
+                }
+                v2 = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v2 = v2+(x[i]-mean);
+                }
+                v2 = AP.Math.Sqr(v2)/n;
+                variance = (v1-v2)/(n-1);
+                if( (double)(variance)<(double)(0) )
+                {
+                    variance = 0;
+                }
+                stddev = Math.Sqrt(variance);
+            }
+            
+            //
+            // Skewness and kurtosis
+            //
+            if( (double)(stddev)!=(double)(0) )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    v = (x[i]-mean)/stddev;
+                    v2 = AP.Math.Sqr(v);
+                    skewness = skewness+v2*v;
+                    kurtosis = kurtosis+AP.Math.Sqr(v2);
+                }
+                skewness = skewness/n;
+                kurtosis = kurtosis/n-3;
+            }
+        }
+
+
+        /*************************************************************************
+        ADev
+
+        Input parameters:
+            X   -   sample (array indexes: [0..N-1])
+            N   -   sample size
+            
+        Output parameters:
+            ADev-   ADev
+
+          -- ALGLIB --
+             Copyright 06.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void calculateadev(ref double[] x,
+            int n,
+            ref double adev)
+        {
+            int i = 0;
+            double mean = 0;
+
+            mean = 0;
+            adev = 0;
+            if( n<=0 )
+            {
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                mean = mean+x[i];
+            }
+            mean = mean/n;
+            
+            //
+            // ADev
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                adev = adev+Math.Abs(x[i]-mean);
+            }
+            adev = adev/n;
+        }
+
+
+        /*************************************************************************
+        Median calculation.
+
+        Input parameters:
+            X   -   sample (array indexes: [0..N-1])
+            N   -   sample size
+
+        Output parameters:
+            Median
+
+          -- ALGLIB --
+             Copyright 06.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void calculatemedian(double[] x,
+            int n,
+            ref double median)
+        {
+            int i = 0;
+            int ir = 0;
+            int j = 0;
+            int l = 0;
+            int midp = 0;
+            int k = 0;
+            double a = 0;
+            double temp = 0;
+            double tval = 0;
+
+            x = (double[])x.Clone();
+
+            
+            //
+            // Some degenerate cases
+            //
+            median = 0;
+            if( n<=0 )
+            {
+                return;
+            }
+            if( n==1 )
+            {
+                median = x[0];
+                return;
+            }
+            if( n==2 )
+            {
+                median = 0.5*(x[0]+x[1]);
+                return;
+            }
+            
+            //
+            // Common case, N>=3.
+            // Choose X[(N-1)/2]
+            //
+            l = 0;
+            ir = n-1;
+            k = (n-1)/2;
+            while( true )
+            {
+                if( ir<=l+1 )
+                {
+                    
+                    //
+                    // 1 or 2 elements in partition
+                    //
+                    if( ir==l+1 & (double)(x[ir])<(double)(x[l]) )
+                    {
+                        tval = x[l];
+                        x[l] = x[ir];
+                        x[ir] = tval;
+                    }
+                    break;
+                }
+                else
+                {
+                    midp = (l+ir)/2;
+                    tval = x[midp];
+                    x[midp] = x[l+1];
+                    x[l+1] = tval;
+                    if( (double)(x[l])>(double)(x[ir]) )
+                    {
+                        tval = x[l];
+                        x[l] = x[ir];
+                        x[ir] = tval;
+                    }
+                    if( (double)(x[l+1])>(double)(x[ir]) )
+                    {
+                        tval = x[l+1];
+                        x[l+1] = x[ir];
+                        x[ir] = tval;
+                    }
+                    if( (double)(x[l])>(double)(x[l+1]) )
+                    {
+                        tval = x[l];
+                        x[l] = x[l+1];
+                        x[l+1] = tval;
+                    }
+                    i = l+1;
+                    j = ir;
+                    a = x[l+1];
+                    while( true )
+                    {
+                        do
+                        {
+                            i = i+1;
+                        }
+                        while( (double)(x[i])<(double)(a) );
+                        do
+                        {
+                            j = j-1;
+                        }
+                        while( (double)(x[j])>(double)(a) );
+                        if( j<i )
+                        {
+                            break;
+                        }
+                        tval = x[i];
+                        x[i] = x[j];
+                        x[j] = tval;
+                    }
+                    x[l+1] = x[j];
+                    x[j] = a;
+                    if( j>=k )
+                    {
+                        ir = j-1;
+                    }
+                    if( j<=k )
+                    {
+                        l = i;
+                    }
+                }
+            }
+            
+            //
+            // If N is odd, return result
+            //
+            if( n%2==1 )
+            {
+                median = x[k];
+                return;
+            }
+            a = x[n-1];
+            for(i=k+1; i<=n-1; i++)
+            {
+                if( (double)(x[i])<(double)(a) )
+                {
+                    a = x[i];
+                }
+            }
+            median = 0.5*(x[k]+a);
+        }
+
+
+        /*************************************************************************
+        Percentile calculation.
+
+        Input parameters:
+            X   -   sample (array indexes: [0..N-1])
+            N   -   sample size, N>1
+            P   -   percentile (0<=P<=1)
+
+        Output parameters:
+            V   -   percentile
+
+          -- ALGLIB --
+             Copyright 01.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void calculatepercentile(double[] x,
+            int n,
+            double p,
+            ref double v)
+        {
+            int i1 = 0;
+            double t = 0;
+
+            x = (double[])x.Clone();
+
+            System.Diagnostics.Debug.Assert(n>1, "CalculatePercentile: N<=1!");
+            System.Diagnostics.Debug.Assert((double)(p)>=(double)(0) & (double)(p)<=(double)(1), "CalculatePercentile: incorrect P!");
+            internalstatheapsort(ref x, n);
+            if( (double)(p)==(double)(0) )
+            {
+                v = x[0];
+                return;
+            }
+            if( (double)(p)==(double)(1) )
+            {
+                v = x[n-1];
+                return;
+            }
+            t = p*(n-1);
+            i1 = (int)Math.Floor(t);
+            t = t-(int)Math.Floor(t);
+            v = x[i1]*(1-t)+x[i1+1]*t;
+        }
+
+
+        private static void internalstatheapsort(ref double[] arr,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+
+            if( n==1 )
+            {
+                return;
+            }
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(arr[k-1])>=(double)(arr[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = arr[k-1];
+                        arr[k-1] = arr[t-1];
+                        arr[t-1] = tmp;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = arr[i];
+                arr[i] = arr[0];
+                arr[0] = tmp;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(arr[k])>(double)(arr[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(arr[t-1])>=(double)(arr[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = arr[k-1];
+                            arr[k-1] = arr[t-1];
+                            arr[t-1] = tmp;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/det.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/det.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/det.cs	(revision 2645)
@@ -0,0 +1,128 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class det
+    {
+        /*************************************************************************
+        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       -   size of matrix A.
+
+        Result: matrix determinant.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static double rmatrixludet(ref double[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            int s = 0;
+
+            result = 1;
+            s = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                result = result*a[i,i];
+                if( pivots[i]!=i )
+                {
+                    s = -s;
+                }
+            }
+            result = result*s;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Calculation of the determinant of a general matrix
+
+        Input parameters:
+            A       -   matrix, array[0..N-1, 0..N-1]
+            N       -   size of matrix A.
+
+        Result: determinant of matrix A.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static double rmatrixdet(double[,] a,
+            int n)
+        {
+            double result = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            lu.rmatrixlu(ref a, n, n, ref pivots);
+            result = rmatrixludet(ref a, ref pivots, n);
+            return result;
+        }
+
+
+        public static double determinantlu(ref double[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            int s = 0;
+
+            result = 1;
+            s = 1;
+            for(i=1; i<=n; i++)
+            {
+                result = result*a[i,i];
+                if( pivots[i]!=i )
+                {
+                    s = -s;
+                }
+            }
+            result = result*s;
+            return result;
+        }
+
+
+        public static double determinant(double[,] a,
+            int n)
+        {
+            double result = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            lu.ludecomposition(ref a, n, n, ref pivots);
+            result = determinantlu(ref a, ref pivots, n);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/dforest.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/dforest.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/dforest.cs	(revision 2645)
@@ -0,0 +1,1857 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class dforest
+    {
+        public struct decisionforest
+        {
+            public int nvars;
+            public int nclasses;
+            public int ntrees;
+            public int bufsize;
+            public double[] trees;
+        };
+
+
+        public struct dfreport
+        {
+            public double relclserror;
+            public double avgce;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+            public double oobrelclserror;
+            public double oobavgce;
+            public double oobrmserror;
+            public double oobavgerror;
+            public double oobavgrelerror;
+        };
+
+
+        public struct dfinternalbuffers
+        {
+            public double[] treebuf;
+            public int[] idxbuf;
+            public double[] tmpbufr;
+            public double[] tmpbufr2;
+            public int[] tmpbufi;
+            public int[] classibuf;
+            public int[] varpool;
+            public bool[] evsbin;
+            public double[] evssplits;
+        };
+
+
+
+
+        public const int dfvnum = 8;
+        public const int innernodewidth = 3;
+        public const int leafnodewidth = 2;
+        public const int dfusestrongsplits = 1;
+        public const int dfuseevs = 2;
+
+
+        /*************************************************************************
+        This subroutine builds random decision forest.
+
+        INPUT PARAMETERS:
+            XY          -   training set
+            NPoints     -   training set size, NPoints>=1
+            NVars       -   number of independent variables, NVars>=1
+            NClasses    -   task type:
+                            * NClasses=1 - regression task with one
+                                           dependent variable
+                            * NClasses>1 - classification task with
+                                           NClasses classes.
+            NTrees      -   number of trees in a forest, NTrees>=1.
+                            recommended values: 50-100.
+            R           -   percent of a training set used to build
+                            individual trees. 0<R<=1.
+                            recommended values: 0.1 <= R <= 0.66.
+
+        OUTPUT PARAMETERS:
+            Info        -   return code:
+                            * -2, if there is a point with class number
+                                  outside of [0..NClasses-1].
+                            * -1, if incorrect parameters was passed
+                                  (NPoints<1, NVars<1, NClasses<1, NTrees<1, R<=0
+                                  or R>1).
+                            *  1, if task has been solved
+            DF          -   model built
+            Rep         -   training report, contains error on a training set
+                            and out-of-bag estimates of generalization error.
+
+          -- ALGLIB --
+             Copyright 19.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dfbuildrandomdecisionforest(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            int ntrees,
+            double r,
+            ref int info,
+            ref decisionforest df,
+            ref dfreport rep)
+        {
+            int samplesize = 0;
+
+            if( (double)(r)<=(double)(0) | (double)(r)>(double)(1) )
+            {
+                info = -1;
+                return;
+            }
+            samplesize = Math.Max((int)Math.Round(r*npoints), 1);
+            dfbuildinternal(ref xy, npoints, nvars, nclasses, ntrees, samplesize, Math.Max(nvars/2, 1), dfusestrongsplits+dfuseevs, ref info, ref df, ref rep);
+        }
+
+
+        public static void dfbuildinternal(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            int ntrees,
+            int samplesize,
+            int nfeatures,
+            int flags,
+            ref int info,
+            ref decisionforest df,
+            ref dfreport rep)
+        {
+            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 = new bool();
+            dfinternalbuffers bufs = new dfinternalbuffers();
+            int[] permbuf = new int[0];
+            double[] oobbuf = new double[0];
+            int[] oobcntbuf = new int[0];
+            double[,] xys = new double[0,0];
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int oobcnt = 0;
+            int oobrelcnt = 0;
+            double v = 0;
+            double vmin = 0;
+            double vmax = 0;
+            bool bflag = new bool();
+            int i_ = 0;
+            int i1_ = 0;
+
+            
+            //
+            // Test for inputs
+            //
+            if( npoints<1 | samplesize<1 | samplesize>npoints | nvars<1 | nclasses<1 | ntrees<1 | nfeatures<1 )
+            {
+                info = -1;
+                return;
+            }
+            if( nclasses>1 )
+            {
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( (int)Math.Round(xy[i,nvars])<0 | (int)Math.Round(xy[i,nvars])>=nclasses )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+            }
+            info = 1;
+            
+            //
+            // Flags
+            //
+            useevs = flags/dfuseevs%2!=0;
+            
+            //
+            // Allocate data, prepare header
+            //
+            treesize = 1+innernodewidth*(samplesize-1)+leafnodewidth*samplesize;
+            permbuf = new int[npoints-1+1];
+            bufs.treebuf = new double[treesize-1+1];
+            bufs.idxbuf = new int[npoints-1+1];
+            bufs.tmpbufr = new double[npoints-1+1];
+            bufs.tmpbufr2 = new double[npoints-1+1];
+            bufs.tmpbufi = new int[npoints-1+1];
+            bufs.varpool = new int[nvars-1+1];
+            bufs.evsbin = new bool[nvars-1+1];
+            bufs.evssplits = new double[nvars-1+1];
+            bufs.classibuf = new int[2*nclasses-1+1];
+            oobbuf = new double[nclasses*npoints-1+1];
+            oobcntbuf = new int[npoints-1+1];
+            df.trees = new double[ntrees*treesize-1+1];
+            xys = new double[samplesize-1+1, nvars+1];
+            x = new double[nvars-1+1];
+            y = new double[nclasses-1+1];
+            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.varpool[i] = i;
+            }
+            nvarsinpool = nvars;
+            if( useevs )
+            {
+                for(j=0; j<=nvars-1; j++)
+                {
+                    vmin = xy[0,j];
+                    vmax = vmin;
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        v = xy[i,j];
+                        vmin = Math.Min(vmin, v);
+                        vmax = Math.Max(vmax, v);
+                    }
+                    if( (double)(vmin)==(double)(vmax) )
+                    {
+                        
+                        //
+                        // exclude variable from pool
+                        //
+                        bufs.varpool[j] = bufs.varpool[nvarsinpool-1];
+                        bufs.varpool[nvarsinpool-1] = -1;
+                        nvarsinpool = nvarsinpool-1;
+                        continue;
+                    }
+                    bflag = false;
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        v = xy[i,j];
+                        if( (double)(v)!=(double)(vmin) & (double)(v)!=(double)(vmax) )
+                        {
+                            bflag = true;
+                            break;
+                        }
+                    }
+                    if( bflag )
+                    {
+                        
+                        //
+                        // non-binary variable
+                        //
+                        bufs.evsbin[j] = false;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Prepare
+                        //
+                        bufs.evsbin[j] = true;
+                        bufs.evssplits[j] = 0.5*(vmin+vmax);
+                        if( (double)(bufs.evssplits[j])<=(double)(vmin) )
+                        {
+                            bufs.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.nvars = nvars;
+            df.nclasses = nclasses;
+            df.ntrees = ntrees;
+            
+            //
+            // Build forest
+            //
+            offs = 0;
+            for(i=0; i<=ntrees-1; i++)
+            {
+                
+                //
+                // Prepare sample
+                //
+                for(k=0; k<=samplesize-1; k++)
+                {
+                    j = k+AP.Math.RandomInteger(npoints-k);
+                    tmpi = permbuf[k];
+                    permbuf[k] = permbuf[j];
+                    permbuf[j] = tmpi;
+                    j = permbuf[k];
+                    for(i_=0; i_<=nvars;i_++)
+                    {
+                        xys[k,i_] = xy[j,i_];
+                    }
+                }
+                
+                //
+                // build tree, copy
+                //
+                dfbuildtree(ref xys, samplesize, nvars, nclasses, nfeatures, nvarsinpool, flags, ref bufs);
+                j = (int)Math.Round(bufs.treebuf[0]);
+                i1_ = (0) - (offs);
+                for(i_=offs; i_<=offs+j-1;i_++)
+                {
+                    df.trees[i_] = bufs.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_];
+                    }
+                    dfprocessinternal(ref df, lasttreeoffs, ref x, ref y);
+                    i1_ = (0) - (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.bufsize = offs;
+            
+            //
+            // Normalize OOB results
+            //
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( oobcntbuf[i]!=0 )
+                {
+                    v = (double)(1)/(double)(oobcntbuf[i]);
+                    for(i_=i*nclasses; i_<=i*nclasses+nclasses-1;i_++)
+                    {
+                        oobbuf[i_] = v*oobbuf[i_];
+                    }
+                }
+            }
+            
+            //
+            // Calculate training set estimates
+            //
+            rep.relclserror = dfrelclserror(ref df, ref xy, npoints);
+            rep.avgce = dfavgce(ref df, ref xy, npoints);
+            rep.rmserror = dfrmserror(ref df, ref xy, npoints);
+            rep.avgerror = dfavgerror(ref df, ref xy, npoints);
+            rep.avgrelerror = dfavgrelerror(ref df, ref xy, npoints);
+            
+            //
+            // Calculate OOB estimates.
+            //
+            rep.oobrelclserror = 0;
+            rep.oobavgce = 0;
+            rep.oobrmserror = 0;
+            rep.oobavgerror = 0;
+            rep.oobavgrelerror = 0;
+            oobcnt = 0;
+            oobrelcnt = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( oobcntbuf[i]!=0 )
+                {
+                    ooboffs = i*nclasses;
+                    if( nclasses>1 )
+                    {
+                        
+                        //
+                        // classification-specific code
+                        //
+                        k = (int)Math.Round(xy[i,nvars]);
+                        tmpi = 0;
+                        for(j=1; j<=nclasses-1; j++)
+                        {
+                            if( (double)(oobbuf[ooboffs+j])>(double)(oobbuf[ooboffs+tmpi]) )
+                            {
+                                tmpi = j;
+                            }
+                        }
+                        if( tmpi!=k )
+                        {
+                            rep.oobrelclserror = rep.oobrelclserror+1;
+                        }
+                        if( (double)(oobbuf[ooboffs+k])!=(double)(0) )
+                        {
+                            rep.oobavgce = rep.oobavgce-Math.Log(oobbuf[ooboffs+k]);
+                        }
+                        else
+                        {
+                            rep.oobavgce = rep.oobavgce-Math.Log(AP.Math.MinRealNumber);
+                        }
+                        for(j=0; j<=nclasses-1; j++)
+                        {
+                            if( j==k )
+                            {
+                                rep.oobrmserror = rep.oobrmserror+AP.Math.Sqr(oobbuf[ooboffs+j]-1);
+                                rep.oobavgerror = rep.oobavgerror+Math.Abs(oobbuf[ooboffs+j]-1);
+                                rep.oobavgrelerror = rep.oobavgrelerror+Math.Abs(oobbuf[ooboffs+j]-1);
+                                oobrelcnt = oobrelcnt+1;
+                            }
+                            else
+                            {
+                                rep.oobrmserror = rep.oobrmserror+AP.Math.Sqr(oobbuf[ooboffs+j]);
+                                rep.oobavgerror = rep.oobavgerror+Math.Abs(oobbuf[ooboffs+j]);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // regression-specific code
+                        //
+                        rep.oobrmserror = rep.oobrmserror+AP.Math.Sqr(oobbuf[ooboffs]-xy[i,nvars]);
+                        rep.oobavgerror = rep.oobavgerror+Math.Abs(oobbuf[ooboffs]-xy[i,nvars]);
+                        if( (double)(xy[i,nvars])!=(double)(0) )
+                        {
+                            rep.oobavgrelerror = rep.oobavgrelerror+Math.Abs((oobbuf[ooboffs]-xy[i,nvars])/xy[i,nvars]);
+                            oobrelcnt = oobrelcnt+1;
+                        }
+                    }
+                    
+                    //
+                    // update OOB estimates count.
+                    //
+                    oobcnt = oobcnt+1;
+                }
+            }
+            if( oobcnt>0 )
+            {
+                rep.oobrelclserror = rep.oobrelclserror/oobcnt;
+                rep.oobavgce = rep.oobavgce/oobcnt;
+                rep.oobrmserror = Math.Sqrt(rep.oobrmserror/(oobcnt*nclasses));
+                rep.oobavgerror = rep.oobavgerror/(oobcnt*nclasses);
+                if( oobrelcnt>0 )
+                {
+                    rep.oobavgrelerror = rep.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.
+                        Subroutine does not allocate memory for this vector, it is
+                        responsibility of a caller to allocate it. Array  must  be
+                        at least [0..NClasses-1].
+
+          -- ALGLIB --
+             Copyright 16.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dfprocess(ref decisionforest df,
+            ref double[] x,
+            ref double[] y)
+        {
+            int offs = 0;
+            int i = 0;
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            // Proceed
+            //
+            offs = 0;
+            for(i=0; i<=df.nclasses-1; i++)
+            {
+                y[i] = 0;
+            }
+            for(i=0; i<=df.ntrees-1; i++)
+            {
+                
+                //
+                // Process basic tree
+                //
+                dfprocessinternal(ref df, offs, ref x, ref y);
+                
+                //
+                // Next tree
+                //
+                offs = offs+(int)Math.Round(df.trees[offs]);
+            }
+            v = (double)(1)/(double)(df.ntrees);
+            for(i_=0; i_<=df.nclasses-1;i_++)
+            {
+                y[i_] = v*y[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Relative classification error on the test set
+
+        INPUT PARAMETERS:
+            DF      -   decision forest model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            percent of incorrectly classified cases.
+            Zero if model solves regression task.
+
+          -- ALGLIB --
+             Copyright 16.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double dfrelclserror(ref decisionforest df,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+
+            result = (double)(dfclserror(ref df, ref xy, npoints))/(double)(npoints);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average cross-entropy (in bits per element) on the test set
+
+        INPUT PARAMETERS:
+            DF      -   decision forest model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            CrossEntropy/(NPoints*LN(2)).
+            Zero if model solves regression task.
+
+          -- ALGLIB --
+             Copyright 16.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double dfavgce(ref decisionforest df,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int tmpi = 0;
+            int i_ = 0;
+
+            x = new double[df.nvars-1+1];
+            y = new double[df.nclasses-1+1];
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=df.nvars-1;i_++)
+                {
+                    x[i_] = xy[i,i_];
+                }
+                dfprocess(ref df, ref x, ref y);
+                if( df.nclasses>1 )
+                {
+                    
+                    //
+                    // classification-specific code
+                    //
+                    k = (int)Math.Round(xy[i,df.nvars]);
+                    tmpi = 0;
+                    for(j=1; j<=df.nclasses-1; j++)
+                    {
+                        if( (double)(y[j])>(double)(y[tmpi]) )
+                        {
+                            tmpi = j;
+                        }
+                    }
+                    if( (double)(y[k])!=(double)(0) )
+                    {
+                        result = result-Math.Log(y[k]);
+                    }
+                    else
+                    {
+                        result = result-Math.Log(AP.Math.MinRealNumber);
+                    }
+                }
+            }
+            result = result/npoints;
+            return result;
+        }
+
+
+        /*************************************************************************
+        RMS error on the test set
+
+        INPUT PARAMETERS:
+            DF      -   decision forest model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            root mean square error.
+            Its meaning for regression task is obvious. As for
+            classification task, RMS error means error when estimating posterior
+            probabilities.
+
+          -- ALGLIB --
+             Copyright 16.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double dfrmserror(ref decisionforest df,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int tmpi = 0;
+            int i_ = 0;
+
+            x = new double[df.nvars-1+1];
+            y = new double[df.nclasses-1+1];
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=df.nvars-1;i_++)
+                {
+                    x[i_] = xy[i,i_];
+                }
+                dfprocess(ref df, ref x, ref y);
+                if( df.nclasses>1 )
+                {
+                    
+                    //
+                    // classification-specific code
+                    //
+                    k = (int)Math.Round(xy[i,df.nvars]);
+                    tmpi = 0;
+                    for(j=1; j<=df.nclasses-1; j++)
+                    {
+                        if( (double)(y[j])>(double)(y[tmpi]) )
+                        {
+                            tmpi = j;
+                        }
+                    }
+                    for(j=0; j<=df.nclasses-1; j++)
+                    {
+                        if( j==k )
+                        {
+                            result = result+AP.Math.Sqr(y[j]-1);
+                        }
+                        else
+                        {
+                            result = result+AP.Math.Sqr(y[j]);
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // regression-specific code
+                    //
+                    result = result+AP.Math.Sqr(y[0]-xy[i,df.nvars]);
+                }
+            }
+            result = Math.Sqrt(result/(npoints*df.nclasses));
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average error on the test set
+
+        INPUT PARAMETERS:
+            DF      -   decision forest model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            Its meaning for regression task is obvious. As for
+            classification task, it means average error when estimating posterior
+            probabilities.
+
+          -- ALGLIB --
+             Copyright 16.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double dfavgerror(ref decisionforest df,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int i_ = 0;
+
+            x = new double[df.nvars-1+1];
+            y = new double[df.nclasses-1+1];
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=df.nvars-1;i_++)
+                {
+                    x[i_] = xy[i,i_];
+                }
+                dfprocess(ref df, ref x, ref y);
+                if( df.nclasses>1 )
+                {
+                    
+                    //
+                    // classification-specific code
+                    //
+                    k = (int)Math.Round(xy[i,df.nvars]);
+                    for(j=0; j<=df.nclasses-1; j++)
+                    {
+                        if( j==k )
+                        {
+                            result = result+Math.Abs(y[j]-1);
+                        }
+                        else
+                        {
+                            result = result+Math.Abs(y[j]);
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // regression-specific code
+                    //
+                    result = result+Math.Abs(y[0]-xy[i,df.nvars]);
+                }
+            }
+            result = result/(npoints*df.nclasses);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average relative error on the test set
+
+        INPUT PARAMETERS:
+            DF      -   decision forest model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            Its meaning for regression task is obvious. As for
+            classification task, it means average relative error when estimating
+            posterior probability of belonging to the correct class.
+
+          -- ALGLIB --
+             Copyright 16.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double dfavgrelerror(ref decisionforest df,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int relcnt = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int i_ = 0;
+
+            x = new double[df.nvars-1+1];
+            y = new double[df.nclasses-1+1];
+            result = 0;
+            relcnt = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=df.nvars-1;i_++)
+                {
+                    x[i_] = xy[i,i_];
+                }
+                dfprocess(ref df, ref x, ref y);
+                if( df.nclasses>1 )
+                {
+                    
+                    //
+                    // classification-specific code
+                    //
+                    k = (int)Math.Round(xy[i,df.nvars]);
+                    for(j=0; j<=df.nclasses-1; j++)
+                    {
+                        if( j==k )
+                        {
+                            result = result+Math.Abs(y[j]-1);
+                            relcnt = relcnt+1;
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // regression-specific code
+                    //
+                    if( (double)(xy[i,df.nvars])!=(double)(0) )
+                    {
+                        result = result+Math.Abs((y[0]-xy[i,df.nvars])/xy[i,df.nvars]);
+                        relcnt = relcnt+1;
+                    }
+                }
+            }
+            if( relcnt>0 )
+            {
+                result = result/relcnt;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Copying of DecisionForest strucure
+
+        INPUT PARAMETERS:
+            DF1 -   original
+
+        OUTPUT PARAMETERS:
+            DF2 -   copy
+
+          -- ALGLIB --
+             Copyright 13.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dfcopy(ref decisionforest df1,
+            ref decisionforest df2)
+        {
+            int i_ = 0;
+
+            df2.nvars = df1.nvars;
+            df2.nclasses = df1.nclasses;
+            df2.ntrees = df1.ntrees;
+            df2.bufsize = df1.bufsize;
+            df2.trees = new double[df1.bufsize-1+1];
+            for(i_=0; i_<=df1.bufsize-1;i_++)
+            {
+                df2.trees[i_] = df1.trees[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of DecisionForest strucure
+
+        INPUT PARAMETERS:
+            DF      -   original
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which stores decision forest,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 13.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dfserialize(ref decisionforest df,
+            ref double[] ra,
+            ref int rlen)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            ra = new double[df.bufsize+5-1+1];
+            ra[0] = dfvnum;
+            ra[1] = df.nvars;
+            ra[2] = df.nclasses;
+            ra[3] = df.ntrees;
+            ra[4] = df.bufsize;
+            i1_ = (0) - (5);
+            for(i_=5; i_<=5+df.bufsize-1;i_++)
+            {
+                ra[i_] = df.trees[i_+i1_];
+            }
+            rlen = 5+df.bufsize;
+        }
+
+
+        /*************************************************************************
+        Unserialization of DecisionForest strucure
+
+        INPUT PARAMETERS:
+            RA      -   real array which stores decision forest
+
+        OUTPUT PARAMETERS:
+            DF      -   restored structure
+
+          -- ALGLIB --
+             Copyright 13.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void dfunserialize(ref double[] ra,
+            ref decisionforest df)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[0])==dfvnum, "DFUnserialize: incorrect array!");
+            df.nvars = (int)Math.Round(ra[1]);
+            df.nclasses = (int)Math.Round(ra[2]);
+            df.ntrees = (int)Math.Round(ra[3]);
+            df.bufsize = (int)Math.Round(ra[4]);
+            df.trees = new double[df.bufsize-1+1];
+            i1_ = (5) - (0);
+            for(i_=0; i_<=df.bufsize-1;i_++)
+            {
+                df.trees[i_] = ra[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Classification error
+        *************************************************************************/
+        private static int dfclserror(ref decisionforest df,
+            ref double[,] xy,
+            int npoints)
+        {
+            int result = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int tmpi = 0;
+            int i_ = 0;
+
+            if( df.nclasses<=1 )
+            {
+                result = 0;
+                return result;
+            }
+            x = new double[df.nvars-1+1];
+            y = new double[df.nclasses-1+1];
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=df.nvars-1;i_++)
+                {
+                    x[i_] = xy[i,i_];
+                }
+                dfprocess(ref df, ref x, ref y);
+                k = (int)Math.Round(xy[i,df.nvars]);
+                tmpi = 0;
+                for(j=1; j<=df.nclasses-1; j++)
+                {
+                    if( (double)(y[j])>(double)(y[tmpi]) )
+                    {
+                        tmpi = j;
+                    }
+                }
+                if( tmpi!=k )
+                {
+                    result = result+1;
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine for processing one decision tree starting at Offs
+        *************************************************************************/
+        private static void dfprocessinternal(ref decisionforest df,
+            int offs,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            int k = 0;
+            int idx = 0;
+
+            
+            //
+            // Set pointer to the root
+            //
+            k = offs+1;
+            
+            //
+            // Navigate through the tree
+            //
+            while( true )
+            {
+                if( (double)(df.trees[k])==(double)(-1) )
+                {
+                    if( df.nclasses==1 )
+                    {
+                        y[0] = y[0]+df.trees[k+1];
+                    }
+                    else
+                    {
+                        idx = (int)Math.Round(df.trees[k+1]);
+                        y[idx] = y[idx]+1;
+                    }
+                    break;
+                }
+                if( (double)(x[(int)Math.Round(df.trees[k])])<(double)(df.trees[k+1]) )
+                {
+                    k = k+innernodewidth;
+                }
+                else
+                {
+                    k = offs+(int)Math.Round(df.trees[k+2]);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Builds one decision tree. Just a wrapper for the DFBuildTreeRec.
+        *************************************************************************/
+        private static void dfbuildtree(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            int nfeatures,
+            int nvarsinpool,
+            int flags,
+            ref dfinternalbuffers bufs)
+        {
+            int numprocessed = 0;
+            int i = 0;
+
+            System.Diagnostics.Debug.Assert(npoints>0);
+            
+            //
+            // Prepare IdxBuf. It stores indices of the training set elements.
+            // When training set is being split, contents of IdxBuf is
+            // correspondingly reordered so we can know which elements belong
+            // to which branch of decision tree.
+            //
+            for(i=0; i<=npoints-1; i++)
+            {
+                bufs.idxbuf[i] = i;
+            }
+            
+            //
+            // Recursive procedure
+            //
+            numprocessed = 1;
+            dfbuildtreerec(ref xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, ref numprocessed, 0, npoints-1, ref bufs);
+            bufs.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
+        *************************************************************************/
+        private static void dfbuildtreerec(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            int nfeatures,
+            int nvarsinpool,
+            int flags,
+            ref int numprocessed,
+            int idx1,
+            int idx2,
+            ref dfinternalbuffers bufs)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            bool bflag = new bool();
+            int offs = 0;
+            int i1 = 0;
+            int i2 = 0;
+            int lsize = 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;
+            int nbuf = 0;
+            double threshold = 0;
+            int oldnp = 0;
+            double e = 0;
+            double currms = 0;
+            double curcvrms = 0;
+            bool useevs = new bool();
+
+            System.Diagnostics.Debug.Assert(npoints>0);
+            System.Diagnostics.Debug.Assert(idx2>=idx1);
+            useevs = flags/dfuseevs%2!=0;
+            
+            //
+            // Leaf node
+            //
+            if( idx2==idx1 )
+            {
+                bufs.treebuf[numprocessed] = -1;
+                bufs.treebuf[numprocessed+1] = xy[bufs.idxbuf[idx1],nvars];
+                numprocessed = numprocessed+leafnodewidth;
+                return;
+            }
+            
+            //
+            // Non-leaf node.
+            // Select random variable, prepare split:
+            // 1. prepare default solution - no splitting, class at random
+            // 2. investigate possible splits, compare with default/best
+            //
+            idxbest = -1;
+            if( nclasses>1 )
+            {
+                
+                //
+                // default solution for classification
+                //
+                for(i=0; i<=nclasses-1; i++)
+                {
+                    bufs.classibuf[i] = 0;
+                }
+                s = idx2-idx1+1;
+                for(i=idx1; i<=idx2; i++)
+                {
+                    j = (int)Math.Round(xy[bufs.idxbuf[i],nvars]);
+                    bufs.classibuf[j] = bufs.classibuf[j]+1;
+                }
+                ebest = 0;
+                for(i=0; i<=nclasses-1; i++)
+                {
+                    ebest = ebest+bufs.classibuf[i]*AP.Math.Sqr(1-bufs.classibuf[i]/s)+(s-bufs.classibuf[i])*AP.Math.Sqr(bufs.classibuf[i]/s);
+                }
+                ebest = Math.Sqrt(ebest/(nclasses*(idx2-idx1+1)));
+            }
+            else
+            {
+                
+                //
+                // default solution for regression
+                //
+                v = 0;
+                for(i=idx1; i<=idx2; i++)
+                {
+                    v = v+xy[bufs.idxbuf[i],nvars];
+                }
+                v = v/(idx2-idx1+1);
+                ebest = 0;
+                for(i=idx1; i<=idx2; i++)
+                {
+                    ebest = ebest+AP.Math.Sqr(xy[bufs.idxbuf[i],nvars]-v);
+                }
+                ebest = Math.Sqrt(ebest/(idx2-idx1+1));
+            }
+            i = 0;
+            while( i<=Math.Min(nfeatures, nvarsinpool)-1 )
+            {
+                
+                //
+                // select variables from pool
+                //
+                j = i+AP.Math.RandomInteger(nvarsinpool-i);
+                k = bufs.varpool[i];
+                bufs.varpool[i] = bufs.varpool[j];
+                bufs.varpool[j] = k;
+                varcur = bufs.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.tmpbufr[j-idx1] = xy[bufs.idxbuf[j],varcur];
+                }
+                if( useevs )
+                {
+                    bflag = false;
+                    v = bufs.tmpbufr[0];
+                    for(j=0; j<=idx2-idx1; j++)
+                    {
+                        if( (double)(bufs.tmpbufr[j])!=(double)(v) )
+                        {
+                            bflag = true;
+                            break;
+                        }
+                    }
+                    if( !bflag )
+                    {
+                        
+                        //
+                        // exclude variable from pool,
+                        // go to the next iteration.
+                        // I is not increased.
+                        //
+                        k = bufs.varpool[i];
+                        bufs.varpool[i] = bufs.varpool[nvarsinpool-1];
+                        bufs.varpool[nvarsinpool-1] = k;
+                        nvarsinpool = nvarsinpool-1;
+                        continue;
+                    }
+                }
+                
+                //
+                // load labels to working array
+                //
+                if( nclasses>1 )
+                {
+                    for(j=idx1; j<=idx2; j++)
+                    {
+                        bufs.tmpbufi[j-idx1] = (int)Math.Round(xy[bufs.idxbuf[j],nvars]);
+                    }
+                }
+                else
+                {
+                    for(j=idx1; j<=idx2; j++)
+                    {
+                        bufs.tmpbufr2[j-idx1] = xy[bufs.idxbuf[j],nvars];
+                    }
+                }
+                
+                //
+                // calculate split
+                //
+                if( useevs & bufs.evsbin[varcur] )
+                {
+                    
+                    //
+                    // Pre-calculated splits for binary variables.
+                    // Threshold is already known, just calculate RMS error
+                    //
+                    threshold = bufs.evssplits[varcur];
+                    if( nclasses>1 )
+                    {
+                        
+                        //
+                        // classification-specific code
+                        //
+                        for(j=0; j<=2*nclasses-1; j++)
+                        {
+                            bufs.classibuf[j] = 0;
+                        }
+                        sl = 0;
+                        sr = 0;
+                        for(j=0; j<=idx2-idx1; j++)
+                        {
+                            k = bufs.tmpbufi[j];
+                            if( (double)(bufs.tmpbufr[j])<(double)(threshold) )
+                            {
+                                bufs.classibuf[k] = bufs.classibuf[k]+1;
+                                sl = sl+1;
+                            }
+                            else
+                            {
+                                bufs.classibuf[k+nclasses] = bufs.classibuf[k+nclasses]+1;
+                                sr = sr+1;
+                            }
+                        }
+                        System.Diagnostics.Debug.Assert((double)(sl)!=(double)(0) & (double)(sr)!=(double)(0), "DFBuildTreeRec: something strange!");
+                        currms = 0;
+                        for(j=0; j<=nclasses-1; j++)
+                        {
+                            w = bufs.classibuf[j];
+                            currms = currms+w*AP.Math.Sqr(w/sl-1);
+                            currms = currms+(sl-w)*AP.Math.Sqr(w/sl);
+                            w = bufs.classibuf[nclasses+j];
+                            currms = currms+w*AP.Math.Sqr(w/sr-1);
+                            currms = currms+(sr-w)*AP.Math.Sqr(w/sr);
+                        }
+                        currms = Math.Sqrt(currms/(nclasses*(idx2-idx1+1)));
+                    }
+                    else
+                    {
+                        
+                        //
+                        // regression-specific code
+                        //
+                        sl = 0;
+                        sr = 0;
+                        v1 = 0;
+                        v2 = 0;
+                        for(j=0; j<=idx2-idx1; j++)
+                        {
+                            if( (double)(bufs.tmpbufr[j])<(double)(threshold) )
+                            {
+                                v1 = v1+bufs.tmpbufr2[j];
+                                sl = sl+1;
+                            }
+                            else
+                            {
+                                v2 = v2+bufs.tmpbufr2[j];
+                                sr = sr+1;
+                            }
+                        }
+                        System.Diagnostics.Debug.Assert((double)(sl)!=(double)(0) & (double)(sr)!=(double)(0), "DFBuildTreeRec: something strange!");
+                        v1 = v1/sl;
+                        v2 = v2/sr;
+                        currms = 0;
+                        for(j=0; j<=idx2-idx1; j++)
+                        {
+                            if( (double)(bufs.tmpbufr[j])<(double)(threshold) )
+                            {
+                                currms = currms+AP.Math.Sqr(v1-bufs.tmpbufr2[j]);
+                            }
+                            else
+                            {
+                                currms = currms+AP.Math.Sqr(v2-bufs.tmpbufr2[j]);
+                            }
+                        }
+                        currms = Math.Sqrt(currms/(idx2-idx1+1));
+                    }
+                    info = 1;
+                }
+                else
+                {
+                    
+                    //
+                    // Generic splits
+                    //
+                    if( nclasses>1 )
+                    {
+                        dfsplitc(ref bufs.tmpbufr, ref bufs.tmpbufi, ref bufs.classibuf, idx2-idx1+1, nclasses, dfusestrongsplits, ref info, ref threshold, ref currms);
+                    }
+                    else
+                    {
+                        dfsplitr(ref bufs.tmpbufr, ref bufs.tmpbufr2, idx2-idx1+1, dfusestrongsplits, ref info, ref threshold, ref currms);
+                    }
+                }
+                if( info>0 )
+                {
+                    if( (double)(currms)<=(double)(ebest) )
+                    {
+                        ebest = currms;
+                        idxbest = varcur;
+                        tbest = threshold;
+                    }
+                }
+                
+                //
+                // Next iteration
+                //
+                i = i+1;
+            }
+            
+            //
+            // to split or not to split
+            //
+            if( idxbest<0 )
+            {
+                
+                //
+                // All values are same, cannot split.
+                //
+                bufs.treebuf[numprocessed] = -1;
+                if( nclasses>1 )
+                {
+                    
+                    //
+                    // Select random class label (randomness allows us to
+                    // approximate distribution of the classes)
+                    //
+                    bufs.treebuf[numprocessed+1] = (int)Math.Round(xy[bufs.idxbuf[idx1+AP.Math.RandomInteger(idx2-idx1+1)],nvars]);
+                }
+                else
+                {
+                    
+                    //
+                    // Select average (for regression task).
+                    //
+                    v = 0;
+                    for(i=idx1; i<=idx2; i++)
+                    {
+                        v = v+xy[bufs.idxbuf[i],nvars]/(idx2-idx1+1);
+                    }
+                    bufs.treebuf[numprocessed+1] = v;
+                }
+                numprocessed = numprocessed+leafnodewidth;
+            }
+            else
+            {
+                
+                //
+                // we can split
+                //
+                bufs.treebuf[numprocessed] = idxbest;
+                bufs.treebuf[numprocessed+1] = tbest;
+                i1 = idx1;
+                i2 = idx2;
+                while( i1<=i2 )
+                {
+                    
+                    //
+                    // Reorder indices so that left partition is in [Idx1..I1-1],
+                    // and right partition is in [I2+1..Idx2]
+                    //
+                    if( (double)(xy[bufs.idxbuf[i1],idxbest])<(double)(tbest) )
+                    {
+                        i1 = i1+1;
+                        continue;
+                    }
+                    if( (double)(xy[bufs.idxbuf[i2],idxbest])>=(double)(tbest) )
+                    {
+                        i2 = i2-1;
+                        continue;
+                    }
+                    j = bufs.idxbuf[i1];
+                    bufs.idxbuf[i1] = bufs.idxbuf[i2];
+                    bufs.idxbuf[i2] = j;
+                    i1 = i1+1;
+                    i2 = i2-1;
+                }
+                oldnp = numprocessed;
+                numprocessed = numprocessed+innernodewidth;
+                dfbuildtreerec(ref xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, ref numprocessed, idx1, i1-1, ref bufs);
+                bufs.treebuf[oldnp+2] = numprocessed;
+                dfbuildtreerec(ref xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, ref numprocessed, i2+1, idx2, ref bufs);
+            }
+        }
+
+
+        /*************************************************************************
+        Makes weak split on attribute
+        *************************************************************************/
+        private static void dfweakspliti(ref double[] x,
+            ref int[] y,
+            int n,
+            int nclasses,
+            ref int info,
+            ref double threshold,
+            ref double e)
+        {
+            int i = 0;
+            int neq = 0;
+            int nless = 0;
+            int ngreater = 0;
+
+            tsort.tagsortfasti(ref x, ref y, n);
+            if( n%2==1 )
+            {
+                
+                //
+                // odd number of elements
+                //
+                threshold = x[n/2];
+            }
+            else
+            {
+                
+                //
+                // even number of elements.
+                //
+                // if two closest to the middle of the array are equal,
+                // we will select one of them (to avoid possible problems with
+                // floating point errors).
+                // we will select halfsum otherwise.
+                //
+                if( (double)(x[n/2-1])==(double)(x[n/2]) )
+                {
+                    threshold = x[n/2-1];
+                }
+                else
+                {
+                    threshold = 0.5*(x[n/2-1]+x[n/2]);
+                }
+            }
+            neq = 0;
+            nless = 0;
+            ngreater = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(x[i])<(double)(threshold) )
+                {
+                    nless = nless+1;
+                }
+                if( (double)(x[i])==(double)(threshold) )
+                {
+                    neq = neq+1;
+                }
+                if( (double)(x[i])>(double)(threshold) )
+                {
+                    ngreater = ngreater+1;
+                }
+            }
+            if( nless==0 & ngreater==0 )
+            {
+                info = -3;
+            }
+            else
+            {
+                if( neq!=0 )
+                {
+                    if( nless<ngreater )
+                    {
+                        threshold = 0.5*(x[nless+neq-1]+x[nless+neq]);
+                    }
+                    else
+                    {
+                        threshold = 0.5*(x[nless-1]+x[nless]);
+                    }
+                }
+                info = 1;
+                e = 0;
+            }
+        }
+
+
+        /*************************************************************************
+        Makes split on attribute
+        *************************************************************************/
+        private static void dfsplitc(ref double[] x,
+            ref int[] c,
+            ref int[] cntbuf,
+            int n,
+            int nc,
+            int flags,
+            ref int info,
+            ref double threshold,
+            ref double e)
+        {
+            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;
+
+            tsort.tagsortfasti(ref x, ref c, n);
+            e = AP.Math.MaxRealNumber;
+            threshold = 0.5*(x[0]+x[n-1]);
+            info = -3;
+            if( flags/dfusestrongsplits%2==0 )
+            {
+                
+                //
+                // weak splits, split at half
+                //
+                qcnt = 2;
+                qmin = 1;
+                qmax = 1;
+            }
+            else
+            {
+                
+                //
+                // strong splits: choose best quartile
+                //
+                qcnt = 4;
+                qmin = 1;
+                qmax = 3;
+            }
+            for(q=qmin; q<=qmax; q++)
+            {
+                cursplit = x[n*q/qcnt];
+                neq = 0;
+                nless = 0;
+                ngreater = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    if( (double)(x[i])<(double)(cursplit) )
+                    {
+                        nless = nless+1;
+                    }
+                    if( (double)(x[i])==(double)(cursplit) )
+                    {
+                        neq = neq+1;
+                    }
+                    if( (double)(x[i])>(double)(cursplit) )
+                    {
+                        ngreater = ngreater+1;
+                    }
+                }
+                System.Diagnostics.Debug.Assert(neq!=0, "DFSplitR: NEq=0, something strange!!!");
+                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<ngreater )
+                    {
+                        cursplit = 0.5*(x[nless+neq-1]+x[nless+neq]);
+                        nleft = nless+neq;
+                        if( (double)(cursplit)<=(double)(x[nless+neq-1]) )
+                        {
+                            cursplit = x[nless+neq];
+                        }
+                    }
+                    else
+                    {
+                        cursplit = 0.5*(x[nless-1]+x[nless]);
+                        nleft = nless;
+                        if( (double)(cursplit)<=(double)(x[nless-1]) )
+                        {
+                            cursplit = x[nless];
+                        }
+                    }
+                    info = 1;
+                    cure = 0;
+                    for(i=0; i<=2*nc-1; i++)
+                    {
+                        cntbuf[i] = 0;
+                    }
+                    for(i=0; i<=nleft-1; i++)
+                    {
+                        cntbuf[c[i]] = cntbuf[c[i]]+1;
+                    }
+                    for(i=nleft; i<=n-1; i++)
+                    {
+                        cntbuf[nc+c[i]] = cntbuf[nc+c[i]]+1;
+                    }
+                    sl = nleft;
+                    sr = n-nleft;
+                    v = 0;
+                    for(i=0; i<=nc-1; i++)
+                    {
+                        w = cntbuf[i];
+                        v = v+w*AP.Math.Sqr(w/sl-1);
+                        v = v+(sl-w)*AP.Math.Sqr(w/sl);
+                        w = cntbuf[nc+i];
+                        v = v+w*AP.Math.Sqr(w/sr-1);
+                        v = v+(sr-w)*AP.Math.Sqr(w/sr);
+                    }
+                    cure = Math.Sqrt(v/(nc*n));
+                    if( (double)(cure)<(double)(e) )
+                    {
+                        threshold = cursplit;
+                        e = cure;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Makes split on attribute
+        *************************************************************************/
+        private static void dfsplitr(ref double[] x,
+            ref double[] y,
+            int n,
+            int flags,
+            ref int info,
+            ref double threshold,
+            ref double e)
+        {
+            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;
+
+            tsort.tagsortfastr(ref x, ref y, n);
+            e = AP.Math.MaxRealNumber;
+            threshold = 0.5*(x[0]+x[n-1]);
+            info = -3;
+            if( flags/dfusestrongsplits%2==0 )
+            {
+                
+                //
+                // weak splits, split at half
+                //
+                qcnt = 2;
+                qmin = 1;
+                qmax = 1;
+            }
+            else
+            {
+                
+                //
+                // strong splits: choose best quartile
+                //
+                qcnt = 4;
+                qmin = 1;
+                qmax = 3;
+            }
+            for(q=qmin; q<=qmax; q++)
+            {
+                cursplit = x[n*q/qcnt];
+                neq = 0;
+                nless = 0;
+                ngreater = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    if( (double)(x[i])<(double)(cursplit) )
+                    {
+                        nless = nless+1;
+                    }
+                    if( (double)(x[i])==(double)(cursplit) )
+                    {
+                        neq = neq+1;
+                    }
+                    if( (double)(x[i])>(double)(cursplit) )
+                    {
+                        ngreater = ngreater+1;
+                    }
+                }
+                System.Diagnostics.Debug.Assert(neq!=0, "DFSplitR: NEq=0, something strange!!!");
+                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<ngreater )
+                    {
+                        cursplit = 0.5*(x[nless+neq-1]+x[nless+neq]);
+                        nleft = nless+neq;
+                        if( (double)(cursplit)<=(double)(x[nless+neq-1]) )
+                        {
+                            cursplit = x[nless+neq];
+                        }
+                    }
+                    else
+                    {
+                        cursplit = 0.5*(x[nless-1]+x[nless]);
+                        nleft = nless;
+                        if( (double)(cursplit)<=(double)(x[nless-1]) )
+                        {
+                            cursplit = x[nless];
+                        }
+                    }
+                    info = 1;
+                    cure = 0;
+                    v = 0;
+                    for(i=0; i<=nleft-1; i++)
+                    {
+                        v = v+y[i];
+                    }
+                    v = v/nleft;
+                    for(i=0; i<=nleft-1; i++)
+                    {
+                        cure = cure+AP.Math.Sqr(y[i]-v);
+                    }
+                    v = 0;
+                    for(i=nleft; i<=n-1; i++)
+                    {
+                        v = v+y[i];
+                    }
+                    v = v/(n-nleft);
+                    for(i=nleft; i<=n-1; i++)
+                    {
+                        cure = cure+AP.Math.Sqr(y[i]-v);
+                    }
+                    cure = Math.Sqrt(cure/n);
+                    if( (double)(cure)<(double)(e) )
+                    {
+                        threshold = cursplit;
+                        e = cure;
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/elliptic.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/elliptic.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/elliptic.cs	(revision 2645)
@@ -0,0 +1,489 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class elliptic
+    {
+        /*************************************************************************
+        Complete elliptic integral of the first kind
+
+        Approximates the integral
+
+
+
+                   pi/2
+                    -
+                   | |
+                   |           dt
+        K(m)  =    |    ------------------
+                   |                   2
+                 | |    sqrt( 1 - m sin t )
+                  -
+                   0
+
+        using the approximation
+
+            P(x)  -  log x Q(x).
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE       0,1        30000       2.5e-16     6.8e-17
+
+        Cephes Math Library, Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double ellipticintegralk(double m)
+        {
+            double result = 0;
+
+            result = ellipticintegralkhighprecision(1.0-m);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complete elliptic integral of the first kind
+
+        Approximates the integral
+
+
+
+                   pi/2
+                    -
+                   | |
+                   |           dt
+        K(m)  =    |    ------------------
+                   |                   2
+                 | |    sqrt( 1 - m sin t )
+                  -
+                   0
+
+        where m = 1 - m1, using the approximation
+
+            P(x)  -  log x Q(x).
+
+        The argument m1 is used rather than m so that the logarithmic
+        singularity at m = 1 will be shifted to the origin; this
+        preserves maximum accuracy.
+
+        K(0) = pi/2.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE       0,1        30000       2.5e-16     6.8e-17
+
+        Àëãîðèòì âçÿò èç áèáëèîòåêè Cephes
+        *************************************************************************/
+        public static double ellipticintegralkhighprecision(double m1)
+        {
+            double result = 0;
+            double p = 0;
+            double q = 0;
+
+            if( (double)(m1)<=(double)(AP.Math.MachineEpsilon) )
+            {
+                result = 1.3862943611198906188E0-0.5*Math.Log(m1);
+            }
+            else
+            {
+                p = 1.37982864606273237150E-4;
+                p = p*m1+2.28025724005875567385E-3;
+                p = p*m1+7.97404013220415179367E-3;
+                p = p*m1+9.85821379021226008714E-3;
+                p = p*m1+6.87489687449949877925E-3;
+                p = p*m1+6.18901033637687613229E-3;
+                p = p*m1+8.79078273952743772254E-3;
+                p = p*m1+1.49380448916805252718E-2;
+                p = p*m1+3.08851465246711995998E-2;
+                p = p*m1+9.65735902811690126535E-2;
+                p = p*m1+1.38629436111989062502E0;
+                q = 2.94078955048598507511E-5;
+                q = q*m1+9.14184723865917226571E-4;
+                q = q*m1+5.94058303753167793257E-3;
+                q = q*m1+1.54850516649762399335E-2;
+                q = q*m1+2.39089602715924892727E-2;
+                q = q*m1+3.01204715227604046988E-2;
+                q = q*m1+3.73774314173823228969E-2;
+                q = q*m1+4.88280347570998239232E-2;
+                q = q*m1+7.03124996963957469739E-2;
+                q = q*m1+1.24999999999870820058E-1;
+                q = q*m1+4.99999999999999999821E-1;
+                result = p-q*Math.Log(m1);
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Incomplete elliptic integral of the first kind F(phi|m)
+
+        Approximates the integral
+
+
+
+                       phi
+                        -
+                       | |
+                       |           dt
+        F(phi_\m)  =    |    ------------------
+                       |                   2
+                     | |    sqrt( 1 - m sin t )
+                      -
+                       0
+
+        of amplitude phi and modulus m, using the arithmetic -
+        geometric mean algorithm.
+
+
+
+
+        ACCURACY:
+
+        Tested at random points with m in [0, 1] and phi as indicated.
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE     -10,10       200000      7.4e-16     1.0e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double incompleteellipticintegralk(double phi,
+            double m)
+        {
+            double result = 0;
+            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;
+
+            pio2 = 1.57079632679489661923;
+            if( (double)(m)==(double)(0) )
+            {
+                result = phi;
+                return result;
+            }
+            a = 1-m;
+            if( (double)(a)==(double)(0) )
+            {
+                result = Math.Log(Math.Tan(0.5*(pio2+phi)));
+                return result;
+            }
+            npio2 = (int)Math.Floor(phi/pio2);
+            if( npio2%2!=0 )
+            {
+                npio2 = npio2+1;
+            }
+            if( npio2!=0 )
+            {
+                k = ellipticintegralk(1-a);
+                phi = phi-npio2*pio2;
+            }
+            else
+            {
+                k = 0;
+            }
+            if( (double)(phi)<(double)(0) )
+            {
+                phi = -phi;
+                s = -1;
+            }
+            else
+            {
+                s = 0;
+            }
+            b = Math.Sqrt(a);
+            t = Math.Tan(phi);
+            if( (double)(Math.Abs(t))>(double)(10) )
+            {
+                e = 1.0/(b*t);
+                if( (double)(Math.Abs(e))<(double)(10) )
+                {
+                    e = Math.Atan(e);
+                    if( npio2==0 )
+                    {
+                        k = ellipticintegralk(1-a);
+                    }
+                    temp = k-incompleteellipticintegralk(e, m);
+                    if( s<0 )
+                    {
+                        temp = -temp;
+                    }
+                    result = temp+npio2*k;
+                    return result;
+                }
+            }
+            a = 1.0;
+            c = Math.Sqrt(m);
+            d = 1;
+            md = 0;
+            while( (double)(Math.Abs(c/a))>(double)(AP.Math.MachineEpsilon) )
+            {
+                temp = b/a;
+                phi = phi+Math.Atan(t*temp)+md*Math.PI;
+                md = (int)((phi+pio2)/Math.PI);
+                t = t*(1.0+temp)/(1.0-temp*t*t);
+                c = 0.5*(a-b);
+                temp = Math.Sqrt(a*b);
+                a = 0.5*(a+b);
+                b = temp;
+                d = d+d;
+            }
+            temp = (Math.Atan(t)+md*Math.PI)/(d*a);
+            if( s<0 )
+            {
+                temp = -temp;
+            }
+            result = temp+npio2*k;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complete elliptic integral of the second kind
+
+        Approximates the integral
+
+
+                   pi/2
+                    -
+                   | |                 2
+        E(m)  =    |    sqrt( 1 - m sin t ) dt
+                 | |
+                  -
+                   0
+
+        using the approximation
+
+             P(x)  -  x log x Q(x).
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE       0, 1       10000       2.1e-16     7.3e-17
+
+        Cephes Math Library, Release 2.8: June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double ellipticintegrale(double m)
+        {
+            double result = 0;
+            double p = 0;
+            double q = 0;
+
+            System.Diagnostics.Debug.Assert((double)(m)>=(double)(0) & (double)(m)<=(double)(1), "Domain error in EllipticIntegralE: m<0 or m>1");
+            m = 1-m;
+            if( (double)(m)==(double)(0) )
+            {
+                result = 1;
+                return result;
+            }
+            p = 1.53552577301013293365E-4;
+            p = p*m+2.50888492163602060990E-3;
+            p = p*m+8.68786816565889628429E-3;
+            p = p*m+1.07350949056076193403E-2;
+            p = p*m+7.77395492516787092951E-3;
+            p = p*m+7.58395289413514708519E-3;
+            p = p*m+1.15688436810574127319E-2;
+            p = p*m+2.18317996015557253103E-2;
+            p = p*m+5.68051945617860553470E-2;
+            p = p*m+4.43147180560990850618E-1;
+            p = p*m+1.00000000000000000299E0;
+            q = 3.27954898576485872656E-5;
+            q = q*m+1.00962792679356715133E-3;
+            q = q*m+6.50609489976927491433E-3;
+            q = q*m+1.68862163993311317300E-2;
+            q = q*m+2.61769742454493659583E-2;
+            q = q*m+3.34833904888224918614E-2;
+            q = q*m+4.27180926518931511717E-2;
+            q = q*m+5.85936634471101055642E-2;
+            q = q*m+9.37499997197644278445E-2;
+            q = q*m+2.49999999999888314361E-1;
+            result = p-q*m*Math.Log(m);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Incomplete elliptic integral of the second kind
+
+        Approximates the integral
+
+
+                       phi
+                        -
+                       | |
+                       |                   2
+        E(phi_\m)  =    |    sqrt( 1 - m sin t ) dt
+                       |
+                     | |
+                      -
+                       0
+
+        of amplitude phi and modulus m, using the arithmetic -
+        geometric mean algorithm.
+
+        ACCURACY:
+
+        Tested at random arguments with phi in [-10, 10] and m in
+        [0, 1].
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE     -10,10      150000       3.3e-15     1.4e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double incompleteellipticintegrale(double phi,
+            double m)
+        {
+            double result = 0;
+            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;
+
+            pio2 = 1.57079632679489661923;
+            if( (double)(m)==(double)(0) )
+            {
+                result = phi;
+                return result;
+            }
+            lphi = phi;
+            npio2 = (int)Math.Floor(lphi/pio2);
+            if( npio2%2!=0 )
+            {
+                npio2 = npio2+1;
+            }
+            lphi = lphi-npio2*pio2;
+            if( (double)(lphi)<(double)(0) )
+            {
+                lphi = -lphi;
+                s = -1;
+            }
+            else
+            {
+                s = 1;
+            }
+            a = 1.0-m;
+            ebig = ellipticintegrale(m);
+            if( (double)(a)==(double)(0) )
+            {
+                temp = Math.Sin(lphi);
+                if( s<0 )
+                {
+                    temp = -temp;
+                }
+                result = temp+npio2*ebig;
+                return result;
+            }
+            t = Math.Tan(lphi);
+            b = Math.Sqrt(a);
+            
+            //
+            // Thanks to Brian Fitzgerald <fitzgb@mml0.meche.rpi.edu>
+            // for pointing out an instability near odd multiples of pi/2
+            //
+            if( (double)(Math.Abs(t))>(double)(10) )
+            {
+                
+                //
+                // Transform the amplitude
+                //
+                e = 1.0/(b*t);
+                
+                //
+                // ... but avoid multiple recursions.
+                //
+                if( (double)(Math.Abs(e))<(double)(10) )
+                {
+                    e = Math.Atan(e);
+                    temp = ebig+m*Math.Sin(lphi)*Math.Sin(e)-incompleteellipticintegrale(e, m);
+                    if( s<0 )
+                    {
+                        temp = -temp;
+                    }
+                    result = temp+npio2*ebig;
+                    return result;
+                }
+            }
+            c = Math.Sqrt(m);
+            a = 1.0;
+            d = 1;
+            e = 0.0;
+            md = 0;
+            while( (double)(Math.Abs(c/a))>(double)(AP.Math.MachineEpsilon) )
+            {
+                temp = b/a;
+                lphi = lphi+Math.Atan(t*temp)+md*Math.PI;
+                md = (int)((lphi+pio2)/Math.PI);
+                t = t*(1.0+temp)/(1.0-temp*t*t);
+                c = 0.5*(a-b);
+                temp = Math.Sqrt(a*b);
+                a = 0.5*(a+b);
+                b = temp;
+                d = d+d;
+                e = e+c*Math.Sin(lphi);
+            }
+            temp = ebig/ellipticintegralk(m);
+            temp = temp*((Math.Atan(t)+md*Math.PI)/(d*a));
+            temp = temp+e;
+            if( s<0 )
+            {
+                temp = -temp;
+            }
+            result = temp+npio2*ebig;
+            return result;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/estnorm.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/estnorm.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/estnorm.cs	(revision 2645)
@@ -0,0 +1,369 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class estnorm
+    {
+        /*************************************************************************
+        Matrix norm estimation
+
+        The algorithm estimates the 1-norm of square matrix A  on  the  assumption
+        that the multiplication of matrix  A  by  the  vector  is  available  (the
+        iterative method is used). It is recommended to use this algorithm  if  it
+        is hard  to  calculate  matrix  elements  explicitly  (for  example,  when
+        estimating the inverse matrix norm).
+
+        The algorithm uses back communication for multiplying the  vector  by  the
+        matrix.  If  KASE=0  after  returning from a subroutine, its execution was
+        completed successfully, otherwise it is required to multiply the  returned
+        vector by matrix A and call the subroutine again.
+
+        The DemoIterativeEstimateNorm subroutine shows a simple example.
+
+        Parameters:
+            N       -   size of matrix A.
+            V       -   vector.   It is initialized by the subroutine on the first
+                        call. It is then passed into it on repeated calls.
+            X       -   if KASE<>0, it contains the vector to be replaced by:
+                            A * X,      if KASE=1
+                            A^T * X,    if KASE=2
+                        Array whose index ranges within [1..N].
+            ISGN    -   vector. It is initialized by the subroutine on  the  first
+                        call. It is then passed into it on repeated calls.
+            EST     -   if KASE=0, it contains the lower boundary of the matrix
+                        norm estimate.
+            KASE    -   on the first call, it should be equal to 0. After the last
+                        return, it is equal to 0 (EST contains the  matrix  norm),
+                        on intermediate returns it can be equal to 1 or 2 depending
+                        on the operation to be performed on vector X.
+
+          -- LAPACK auxiliary routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             February 29, 1992
+        *************************************************************************/
+        public static void iterativeestimate1norm(int n,
+            ref double[] v,
+            ref double[] x,
+            ref int[] isgn,
+            ref double est,
+            ref int kase)
+        {
+            int itmax = 0;
+            int i = 0;
+            double t = 0;
+            bool flg = new bool();
+            int positer = 0;
+            int posj = 0;
+            int posjlast = 0;
+            int posjump = 0;
+            int posaltsgn = 0;
+            int posestold = 0;
+            int postemp = 0;
+            int i_ = 0;
+
+            itmax = 5;
+            posaltsgn = n+1;
+            posestold = n+2;
+            postemp = n+3;
+            positer = n+1;
+            posj = n+2;
+            posjlast = n+3;
+            posjump = n+4;
+            if( kase==0 )
+            {
+                v = new double[n+3+1];
+                x = new double[n+1];
+                isgn = new int[n+4+1];
+                t = (double)(1)/(double)(n);
+                for(i=1; i<=n; i++)
+                {
+                    x[i] = t;
+                }
+                kase = 1;
+                isgn[posjump] = 1;
+                return;
+            }
+            
+            //
+            //     ................ ENTRY   (JUMP = 1)
+            //     FIRST ITERATION.  X HAS BEEN OVERWRITTEN BY A*X.
+            //
+            if( isgn[posjump]==1 )
+            {
+                if( n==1 )
+                {
+                    v[1] = x[1];
+                    est = Math.Abs(v[1]);
+                    kase = 0;
+                    return;
+                }
+                est = 0;
+                for(i=1; i<=n; i++)
+                {
+                    est = est+Math.Abs(x[i]);
+                }
+                for(i=1; i<=n; i++)
+                {
+                    if( (double)(x[i])>=(double)(0) )
+                    {
+                        x[i] = 1;
+                    }
+                    else
+                    {
+                        x[i] = -1;
+                    }
+                    isgn[i] = Math.Sign(x[i]);
+                }
+                kase = 2;
+                isgn[posjump] = 2;
+                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++)
+                {
+                    if( (double)(Math.Abs(x[i]))>(double)(Math.Abs(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;
+                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;
+                est = 0;
+                for(i=1; i<=n; i++)
+                {
+                    est = est+Math.Abs(v[i]);
+                }
+                flg = false;
+                for(i=1; i<=n; i++)
+                {
+                    if( (double)(x[i])>=(double)(0) & isgn[i]<0 | (double)(x[i])<(double)(0) & isgn[i]>=0 )
+                    {
+                        flg = true;
+                    }
+                }
+                
+                //
+                // REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED.
+                // OR MAY BE CYCLING.
+                //
+                if( !flg | (double)(est)<=(double)(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;
+                    return;
+                }
+                for(i=1; i<=n; i++)
+                {
+                    if( (double)(x[i])>=(double)(0) )
+                    {
+                        x[i] = 1;
+                        isgn[i] = 1;
+                    }
+                    else
+                    {
+                        x[i] = -1;
+                        isgn[i] = -1;
+                    }
+                }
+                kase = 2;
+                isgn[posjump] = 4;
+                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++)
+                {
+                    if( (double)(Math.Abs(x[i]))>(double)(Math.Abs(x[isgn[posj]])) )
+                    {
+                        isgn[posj] = i;
+                    }
+                }
+                if( (double)(x[isgn[posjlast]])!=(double)(Math.Abs(x[isgn[posj]])) & isgn[positer]<itmax )
+                {
+                    isgn[positer] = isgn[positer]+1;
+                    for(i=1; i<=n; i++)
+                    {
+                        x[i] = 0;
+                    }
+                    x[isgn[posj]] = 1;
+                    kase = 1;
+                    isgn[posjump] = 3;
+                    return;
+                }
+                
+                //
+                // ITERATION COMPLETE.  FINAL STAGE.
+                //
+                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;
+                return;
+            }
+            
+            //
+            //     ................ ENTRY   (JUMP = 5)
+            //     X HAS BEEN OVERWRITTEN BY A*X.
+            //
+            if( isgn[posjump]==5 )
+            {
+                v[postemp] = 0;
+                for(i=1; i<=n; i++)
+                {
+                    v[postemp] = v[postemp]+Math.Abs(x[i]);
+                }
+                v[postemp] = 2*v[postemp]/(3*n);
+                if( (double)(v[postemp])>(double)(est) )
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        v[i_] = x[i_];
+                    }
+                    est = v[postemp];
+                }
+                kase = 0;
+                return;
+            }
+        }
+
+
+        /*************************************************************************
+        Example of usage of an IterativeEstimateNorm subroutine
+
+        Input parameters:
+            A   -   matrix.
+                    Array whose indexes range within [1..N, 1..N].
+
+        Return:
+            Matrix norm estimated by the subroutine.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static double demoiterativeestimate1norm(ref double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            double s = 0;
+            double[] x = new double[0];
+            double[] t = new double[0];
+            double[] v = new double[0];
+            int[] iv = new int[0];
+            int kase = 0;
+            int i_ = 0;
+
+            kase = 0;
+            t = new double[n+1];
+            iterativeestimate1norm(n, ref v, ref x, ref iv, ref result, ref kase);
+            while( kase!=0 )
+            {
+                if( kase==1 )
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        s = 0.0;
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            s += a[i,i_]*x[i_];
+                        }
+                        t[i] = s;
+                    }
+                }
+                else
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        s = 0.0;
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            s += a[i_,i]*x[i_];
+                        }
+                        t[i] = s;
+                    }
+                }
+                for(i_=1; i_<=n;i_++)
+                {
+                    x[i_] = t[i_];
+                }
+                iterativeestimate1norm(n, ref v, ref x, ref iv, ref result, ref kase);
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/expintegrals.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/expintegrals.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/expintegrals.cs	(revision 2645)
@@ -0,0 +1,413 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class expintegrals
+    {
+        /*************************************************************************
+        Exponential integral Ei(x)
+
+                      x
+                       -     t
+                      | |   e
+           Ei(x) =   -|-   ---  dt .
+                    | |     t
+                     -
+                    -inf
+
+        Not defined for x <= 0.
+        See also expn.c.
+
+
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE       0,100       50000      8.6e-16     1.3e-16
+
+        Cephes Math Library Release 2.8:  May, 1999
+        Copyright 1999 by Stephen L. Moshier
+        *************************************************************************/
+        public static double exponentialintegralei(double x)
+        {
+            double result = 0;
+            double eul = 0;
+            double f = 0;
+            double f1 = 0;
+            double f2 = 0;
+            double w = 0;
+
+            eul = 0.5772156649015328606065;
+            if( (double)(x)<=(double)(0) )
+            {
+                result = 0;
+                return result;
+            }
+            if( (double)(x)<(double)(2) )
+            {
+                f1 = -5.350447357812542947283;
+                f1 = f1*x+218.5049168816613393830;
+                f1 = f1*x-4176.572384826693777058;
+                f1 = f1*x+55411.76756393557601232;
+                f1 = f1*x-331338.1331178144034309;
+                f1 = f1*x+1592627.163384945414220;
+                f2 = 1.000000000000000000000;
+                f2 = f2*x-52.50547959112862969197;
+                f2 = f2*x+1259.616186786790571525;
+                f2 = f2*x-17565.49581973534652631;
+                f2 = f2*x+149306.2117002725991967;
+                f2 = f2*x-729494.9239640527645655;
+                f2 = f2*x+1592627.163384945429726;
+                f = f1/f2;
+                result = eul+Math.Log(x)+x*f;
+                return result;
+            }
+            if( (double)(x)<(double)(4) )
+            {
+                w = 1/x;
+                f1 = 1.981808503259689673238E-2;
+                f1 = f1*w-1.271645625984917501326;
+                f1 = f1*w-2.088160335681228318920;
+                f1 = f1*w+2.755544509187936721172;
+                f1 = f1*w-4.409507048701600257171E-1;
+                f1 = f1*w+4.665623805935891391017E-2;
+                f1 = f1*w-1.545042679673485262580E-3;
+                f1 = f1*w+7.059980605299617478514E-5;
+                f2 = 1.000000000000000000000;
+                f2 = f2*w+1.476498670914921440652;
+                f2 = f2*w+5.629177174822436244827E-1;
+                f2 = f2*w+1.699017897879307263248E-1;
+                f2 = f2*w+2.291647179034212017463E-2;
+                f2 = f2*w+4.450150439728752875043E-3;
+                f2 = f2*w+1.727439612206521482874E-4;
+                f2 = f2*w+3.953167195549672482304E-5;
+                f = f1/f2;
+                result = Math.Exp(x)*w*(1+w*f);
+                return result;
+            }
+            if( (double)(x)<(double)(8) )
+            {
+                w = 1/x;
+                f1 = -1.373215375871208729803;
+                f1 = f1*w-7.084559133740838761406E-1;
+                f1 = f1*w+1.580806855547941010501;
+                f1 = f1*w-2.601500427425622944234E-1;
+                f1 = f1*w+2.994674694113713763365E-2;
+                f1 = f1*w-1.038086040188744005513E-3;
+                f1 = f1*w+4.371064420753005429514E-5;
+                f1 = f1*w+2.141783679522602903795E-6;
+                f2 = 1.000000000000000000000;
+                f2 = f2*w+8.585231423622028380768E-1;
+                f2 = f2*w+4.483285822873995129957E-1;
+                f2 = f2*w+7.687932158124475434091E-2;
+                f2 = f2*w+2.449868241021887685904E-2;
+                f2 = f2*w+8.832165941927796567926E-4;
+                f2 = f2*w+4.590952299511353531215E-4;
+                f2 = f2*w+-4.729848351866523044863E-6;
+                f2 = f2*w+2.665195537390710170105E-6;
+                f = f1/f2;
+                result = Math.Exp(x)*w*(1+w*f);
+                return result;
+            }
+            if( (double)(x)<(double)(16) )
+            {
+                w = 1/x;
+                f1 = -2.106934601691916512584;
+                f1 = f1*w+1.732733869664688041885;
+                f1 = f1*w-2.423619178935841904839E-1;
+                f1 = f1*w+2.322724180937565842585E-2;
+                f1 = f1*w+2.372880440493179832059E-4;
+                f1 = f1*w-8.343219561192552752335E-5;
+                f1 = f1*w+1.363408795605250394881E-5;
+                f1 = f1*w-3.655412321999253963714E-7;
+                f1 = f1*w+1.464941733975961318456E-8;
+                f1 = f1*w+6.176407863710360207074E-10;
+                f2 = 1.000000000000000000000;
+                f2 = f2*w-2.298062239901678075778E-1;
+                f2 = f2*w+1.105077041474037862347E-1;
+                f2 = f2*w-1.566542966630792353556E-2;
+                f2 = f2*w+2.761106850817352773874E-3;
+                f2 = f2*w-2.089148012284048449115E-4;
+                f2 = f2*w+1.708528938807675304186E-5;
+                f2 = f2*w-4.459311796356686423199E-7;
+                f2 = f2*w+1.394634930353847498145E-8;
+                f2 = f2*w+6.150865933977338354138E-10;
+                f = f1/f2;
+                result = Math.Exp(x)*w*(1+w*f);
+                return result;
+            }
+            if( (double)(x)<(double)(32) )
+            {
+                w = 1/x;
+                f1 = -2.458119367674020323359E-1;
+                f1 = f1*w-1.483382253322077687183E-1;
+                f1 = f1*w+7.248291795735551591813E-2;
+                f1 = f1*w-1.348315687380940523823E-2;
+                f1 = f1*w+1.342775069788636972294E-3;
+                f1 = f1*w-7.942465637159712264564E-5;
+                f1 = f1*w+2.644179518984235952241E-6;
+                f1 = f1*w-4.239473659313765177195E-8;
+                f2 = 1.000000000000000000000;
+                f2 = f2*w-1.044225908443871106315E-1;
+                f2 = f2*w-2.676453128101402655055E-1;
+                f2 = f2*w+9.695000254621984627876E-2;
+                f2 = f2*w-1.601745692712991078208E-2;
+                f2 = f2*w+1.496414899205908021882E-3;
+                f2 = f2*w-8.462452563778485013756E-5;
+                f2 = f2*w+2.728938403476726394024E-6;
+                f2 = f2*w-4.239462431819542051337E-8;
+                f = f1/f2;
+                result = Math.Exp(x)*w*(1+w*f);
+                return result;
+            }
+            if( (double)(x)<(double)(64) )
+            {
+                w = 1/x;
+                f1 = 1.212561118105456670844E-1;
+                f1 = f1*w-5.823133179043894485122E-1;
+                f1 = f1*w+2.348887314557016779211E-1;
+                f1 = f1*w-3.040034318113248237280E-2;
+                f1 = f1*w+1.510082146865190661777E-3;
+                f1 = f1*w-2.523137095499571377122E-5;
+                f2 = 1.000000000000000000000;
+                f2 = f2*w-1.002252150365854016662;
+                f2 = f2*w+2.928709694872224144953E-1;
+                f2 = f2*w-3.337004338674007801307E-2;
+                f2 = f2*w+1.560544881127388842819E-3;
+                f2 = f2*w-2.523137093603234562648E-5;
+                f = f1/f2;
+                result = Math.Exp(x)*w*(1+w*f);
+                return result;
+            }
+            w = 1/x;
+            f1 = -7.657847078286127362028E-1;
+            f1 = f1*w+6.886192415566705051750E-1;
+            f1 = f1*w-2.132598113545206124553E-1;
+            f1 = f1*w+3.346107552384193813594E-2;
+            f1 = f1*w-3.076541477344756050249E-3;
+            f1 = f1*w+1.747119316454907477380E-4;
+            f1 = f1*w-6.103711682274170530369E-6;
+            f1 = f1*w+1.218032765428652199087E-7;
+            f1 = f1*w-1.086076102793290233007E-9;
+            f2 = 1.000000000000000000000;
+            f2 = f2*w-1.888802868662308731041;
+            f2 = f2*w+1.066691687211408896850;
+            f2 = f2*w-2.751915982306380647738E-1;
+            f2 = f2*w+3.930852688233823569726E-2;
+            f2 = f2*w-3.414684558602365085394E-3;
+            f2 = f2*w+1.866844370703555398195E-4;
+            f2 = f2*w-6.345146083130515357861E-6;
+            f2 = f2*w+1.239754287483206878024E-7;
+            f2 = f2*w-1.086076102793126632978E-9;
+            f = f1/f2;
+            result = Math.Exp(x)*w*(1+w*f);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Exponential integral En(x)
+
+        Evaluates the exponential integral
+
+                        inf.
+                          -
+                         | |   -xt
+                         |    e
+             E (x)  =    |    ----  dt.
+              n          |      n
+                       | |     t
+                        -
+                         1
+
+
+        Both n and x must be nonnegative.
+
+        The routine employs either a power series, a continued
+        fraction, or an asymptotic formula depending on the
+        relative values of n and x.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0, 30       10000       1.7e-15     3.6e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1985, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double exponentialintegralen(double x,
+            int n)
+        {
+            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;
+
+            eul = 0.57721566490153286060;
+            big = 1.44115188075855872*Math.Pow(10, 17);
+            if( n<0 | (double)(x)<(double)(0) | (double)(x)>(double)(170) | (double)(x)==(double)(0) & n<2 )
+            {
+                result = -1;
+                return result;
+            }
+            if( (double)(x)==(double)(0) )
+            {
+                result = (double)(1)/((double)(n-1));
+                return result;
+            }
+            if( n==0 )
+            {
+                result = Math.Exp(-x)/x;
+                return result;
+            }
+            if( n>5000 )
+            {
+                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)*Math.Exp(-x)/xk;
+                return result;
+            }
+            if( (double)(x)<=(double)(1) )
+            {
+                psi = -eul-Math.Log(x);
+                for(i=1; i<=n-1; i++)
+                {
+                    psi = psi+(double)(1)/(double)(i);
+                }
+                z = -x;
+                xk = 0;
+                yk = 1;
+                pk = 1-n;
+                if( n==1 )
+                {
+                    result = 0.0;
+                }
+                else
+                {
+                    result = 1.0/pk;
+                }
+                do
+                {
+                    xk = xk+1;
+                    yk = yk*z/xk;
+                    pk = pk+1;
+                    if( (double)(pk)!=(double)(0) )
+                    {
+                        result = result+yk/pk;
+                    }
+                    if( (double)(result)!=(double)(0) )
+                    {
+                        t = Math.Abs(yk/result);
+                    }
+                    else
+                    {
+                        t = 1;
+                    }
+                }
+                while( (double)(t)>=(double)(AP.Math.MachineEpsilon) );
+                t = 1;
+                for(i=1; i<=n-1; i++)
+                {
+                    t = t*z/i;
+                }
+                result = psi*t-result;
+                return result;
+            }
+            else
+            {
+                k = 1;
+                pkm2 = 1;
+                qkm2 = x;
+                pkm1 = 1.0;
+                qkm1 = x+n;
+                result = pkm1/qkm1;
+                do
+                {
+                    k = k+1;
+                    if( k%2==1 )
+                    {
+                        yk = 1;
+                        xk = n+((double)(k-1))/(double)(2);
+                    }
+                    else
+                    {
+                        yk = x;
+                        xk = (double)(k)/(double)(2);
+                    }
+                    pk = pkm1*yk+pkm2*xk;
+                    qk = qkm1*yk+qkm2*xk;
+                    if( (double)(qk)!=(double)(0) )
+                    {
+                        r = pk/qk;
+                        t = Math.Abs((result-r)/r);
+                        result = r;
+                    }
+                    else
+                    {
+                        t = 1;
+                    }
+                    pkm2 = pkm1;
+                    pkm1 = pk;
+                    qkm2 = qkm1;
+                    qkm1 = qk;
+                    if( (double)(Math.Abs(pk))>(double)(big) )
+                    {
+                        pkm2 = pkm2/big;
+                        pkm1 = pkm1/big;
+                        qkm2 = qkm2/big;
+                        qkm1 = qkm1/big;
+                    }
+                }
+                while( (double)(t)>=(double)(AP.Math.MachineEpsilon) );
+                result = result*Math.Exp(-x);
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fdistr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fdistr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fdistr.cs	(revision 2645)
@@ -0,0 +1,198 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class fdistr
+    {
+        /*************************************************************************
+        F distribution
+
+        Returns the area from zero to x under the F density
+        function (also known as Snedcor's density or the
+        variance ratio density).  This is the density
+        of x = (u1/df1)/(u2/df2), where u1 and u2 are random
+        variables having Chi square distributions with df1
+        and df2 degrees of freedom, respectively.
+        The incomplete beta integral is used, according to the
+        formula
+
+        P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ).
+
+
+        The arguments a and b are greater than zero, and x is
+        nonnegative.
+
+        ACCURACY:
+
+        Tested at random points (a,b,x).
+
+                       x     a,b                     Relative error:
+        arithmetic  domain  domain     # trials      peak         rms
+           IEEE      0,1    0,100       100000      9.8e-15     1.7e-15
+           IEEE      1,5    0,100       100000      6.5e-15     3.5e-16
+           IEEE      0,1    1,10000     100000      2.2e-11     3.3e-12
+           IEEE      1,5    1,10000     100000      1.1e-11     1.7e-13
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double fdistribution(int a,
+            int b,
+            double x)
+        {
+            double result = 0;
+            double w = 0;
+
+            System.Diagnostics.Debug.Assert(a>=1 & b>=1 & (double)(x)>=(double)(0), "Domain error in FDistribution");
+            w = a*x;
+            w = w/(b+w);
+            result = ibetaf.incompletebeta(0.5*a, 0.5*b, w);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complemented F distribution
+
+        Returns the area from x to infinity under the F density
+        function (also known as Snedcor's density or the
+        variance ratio density).
+
+
+                             inf.
+                              -
+                     1       | |  a-1      b-1
+        1-P(x)  =  ------    |   t    (1-t)    dt
+                   B(a,b)  | |
+                            -
+                             x
+
+
+        The incomplete beta integral is used, according to the
+        formula
+
+        P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ).
+
+
+        ACCURACY:
+
+        Tested at random points (a,b,x) in the indicated intervals.
+                       x     a,b                     Relative error:
+        arithmetic  domain  domain     # trials      peak         rms
+           IEEE      0,1    1,100       100000      3.7e-14     5.9e-16
+           IEEE      1,5    1,100       100000      8.0e-15     1.6e-15
+           IEEE      0,1    1,10000     100000      1.8e-11     3.5e-13
+           IEEE      1,5    1,10000     100000      2.0e-11     3.0e-12
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double fcdistribution(int a,
+            int b,
+            double x)
+        {
+            double result = 0;
+            double w = 0;
+
+            System.Diagnostics.Debug.Assert(a>=1 & b>=1 & (double)(x)>=(double)(0), "Domain error in FCDistribution");
+            w = b/(b+a*x);
+            result = ibetaf.incompletebeta(0.5*b, 0.5*a, w);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse of complemented F distribution
+
+        Finds the F density argument x such that the integral
+        from x to infinity of the F density is equal to the
+        given probability p.
+
+        This is accomplished using the inverse beta integral
+        function and the relations
+
+             z = incbi( df2/2, df1/2, p )
+             x = df2 (1-z) / (df1 z).
+
+        Note: the following relations hold for the inverse of
+        the uncomplemented F distribution:
+
+             z = incbi( df1/2, df2/2, p )
+             x = df2 z / (df1 (1-z)).
+
+        ACCURACY:
+
+        Tested at random points (a,b,p).
+
+                     a,b                     Relative error:
+        arithmetic  domain     # trials      peak         rms
+         For p between .001 and 1:
+           IEEE     1,100       100000      8.3e-15     4.7e-16
+           IEEE     1,10000     100000      2.1e-11     1.4e-13
+         For p between 10^-6 and 10^-3:
+           IEEE     1,100        50000      1.3e-12     8.4e-15
+           IEEE     1,10000      50000      3.0e-12     4.8e-14
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invfdistribution(int a,
+            int b,
+            double y)
+        {
+            double result = 0;
+            double w = 0;
+            double x = 0;
+
+            System.Diagnostics.Debug.Assert(a>=1 & b>=1 & (double)(y)>(double)(0) & (double)(y)<=(double)(1), "Domain error in InvFDistribution");
+            
+            //
+            // Compute probability for x = 0.5
+            //
+            w = ibetaf.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( (double)(w)>(double)(y) | (double)(y)<(double)(0.001) )
+            {
+                w = ibetaf.invincompletebeta(0.5*b, 0.5*a, y);
+                result = (b-b*w)/(a*w);
+            }
+            else
+            {
+                w = ibetaf.invincompletebeta(0.5*a, 0.5*b, 1.0-y);
+                result = b*w/(a*(1.0-w));
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fft.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fft.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fft.cs	(revision 2645)
@@ -0,0 +1,482 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class fft
+    {
+        /*************************************************************************
+        1-dimensional complex FFT.
+
+        Array size N may be arbitrary number (composite or prime).  Composite  N's
+        are handled with cache-oblivious variation of  a  Cooley-Tukey  algorithm.
+        Small prime-factors are transformed using hard coded  codelets (similar to
+        FFTW codelets, but without low-level  optimization),  large  prime-factors
+        are handled with Bluestein's algorithm.
+
+        Fastests transforms are for smooth N's (prime factors are 2, 3,  5  only),
+        most fast for powers of 2. When N have prime factors  larger  than  these,
+        but orders of magnitude smaller than N, computations will be about 4 times
+        slower than for nearby highly composite N's. When N itself is prime, speed
+        will be 6 times lower.
+
+        Algorithm has O(N*logN) complexity for any N (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..N-1] - complex function to be transformed
+            N   -   problem size
+            
+        OUTPUT PARAMETERS
+            A   -   DFT of a input array, array[0..N-1]
+                    A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
+
+
+          -- ALGLIB --
+             Copyright 29.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fftc1d(ref AP.Complex[] a,
+            int n)
+        {
+            ftbase.ftplan plan = new ftbase.ftplan();
+            int i = 0;
+            double[] buf = new double[0];
+
+            System.Diagnostics.Debug.Assert(n>0, "FFTC1D: incorrect N!");
+            
+            //
+            // Special case: N=1, FFT is just identity transform.
+            // After this block we assume that N is strictly greater than 1.
+            //
+            if( n==1 )
+            {
+                return;
+            }
+            
+            //
+            // convert input array to the more convinient format
+            //
+            buf = new double[2*n];
+            for(i=0; i<=n-1; i++)
+            {
+                buf[2*i+0] = a[i].x;
+                buf[2*i+1] = a[i].y;
+            }
+            
+            //
+            // Generate plan and execute it.
+            //
+            // Plan is a combination of a successive factorizations of N and
+            // precomputed data. It is much like a FFTW plan, but is not stored
+            // between subroutine calls and is much simpler.
+            //
+            ftbase.ftbasegeneratecomplexfftplan(n, ref plan);
+            ftbase.ftbaseexecuteplan(ref buf, 0, n, ref plan);
+            
+            //
+            // result
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                a[i].x = buf[2*i+0];
+                a[i].y = buf[2*i+1];
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional complex inverse FFT.
+
+        Array size N may be arbitrary number (composite or prime).  Algorithm  has
+        O(N*logN) complexity for any N (composite or prime).
+
+        See FFTC1D() description for more information about algorithm performance.
+
+        INPUT PARAMETERS
+            A   -   array[0..N-1] - complex array to be transformed
+            N   -   problem size
+
+        OUTPUT PARAMETERS
+            A   -   inverse DFT of a input array, array[0..N-1]
+                    A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
+
+
+          -- ALGLIB --
+             Copyright 29.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fftc1dinv(ref AP.Complex[] a,
+            int n)
+        {
+            int i = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "FFTC1DInv: incorrect N!");
+            
+            //
+            // Inverse DFT can be expressed in terms of the DFT as
+            //
+            //     invfft(x) = fft(x')'/N
+            //
+            // here x' means conj(x).
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                a[i].y = -a[i].y;
+            }
+            fftc1d(ref a, n);
+            for(i=0; i<=n-1; i++)
+            {
+                a[i].x = a[i].x/n;
+                a[i].y = -(a[i].y/n);
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional real FFT.
+
+        Algorithm has O(N*logN) complexity for any N (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..N-1] - real function to be transformed
+            N   -   problem size
+
+        OUTPUT PARAMETERS
+            F   -   DFT of a input array, array[0..N-1]
+                    F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
+
+        NOTE:
+            F[] satisfies symmetry property F[k] = conj(F[N-k]),  so just one half
+        of  array  is  usually needed. But for convinience subroutine returns full
+        complex array (with frequencies above N/2), so its result may be  used  by
+        other FFT-related subroutines.
+
+
+          -- ALGLIB --
+             Copyright 01.06.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fftr1d(ref double[] a,
+            int n,
+            ref AP.Complex[] f)
+        {
+            int i = 0;
+            int n2 = 0;
+            int idx = 0;
+            AP.Complex hn = 0;
+            AP.Complex hmnc = 0;
+            AP.Complex v = 0;
+            double[] buf = new double[0];
+            ftbase.ftplan plan = new ftbase.ftplan();
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "FFTR1D: incorrect N!");
+            
+            //
+            // Special cases:
+            // * N=1, FFT is just identity transform.
+            // * N=2, FFT is simple too
+            //
+            // After this block we assume that N is strictly greater than 2
+            //
+            if( n==1 )
+            {
+                f = new AP.Complex[1];
+                f[0] = a[0];
+                return;
+            }
+            if( n==2 )
+            {
+                f = new AP.Complex[2];
+                f[0].x = a[0]+a[1];
+                f[0].y = 0;
+                f[1].x = a[0]-a[1];
+                f[1].y = 0;
+                return;
+            }
+            
+            //
+            // Choose between odd-size and even-size FFTs
+            //
+            if( n%2==0 )
+            {
+                
+                //
+                // even-size real FFT, use reduction to the complex task
+                //
+                n2 = n/2;
+                buf = new double[n];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    buf[i_] = a[i_];
+                }
+                ftbase.ftbasegeneratecomplexfftplan(n2, ref plan);
+                ftbase.ftbaseexecuteplan(ref buf, 0, n2, ref plan);
+                f = new AP.Complex[n];
+                for(i=0; i<=n2; i++)
+                {
+                    idx = 2*(i%n2);
+                    hn.x = buf[idx+0];
+                    hn.y = buf[idx+1];
+                    idx = 2*((n2-i)%n2);
+                    hmnc.x = buf[idx+0];
+                    hmnc.y = -buf[idx+1];
+                    v.x = -Math.Sin(-(2*Math.PI*i/n));
+                    v.y = Math.Cos(-(2*Math.PI*i/n));
+                    f[i] = hn+hmnc-v*(hn-hmnc);
+                    f[i].x = 0.5*f[i].x;
+                    f[i].y = 0.5*f[i].y;
+                }
+                for(i=n2+1; i<=n-1; i++)
+                {
+                    f[i] = AP.Math.Conj(f[n-i]);
+                }
+                return;
+            }
+            else
+            {
+                
+                //
+                // use complex FFT
+                //
+                f = new AP.Complex[n];
+                for(i=0; i<=n-1; i++)
+                {
+                    f[i] = a[i];
+                }
+                fftc1d(ref f, n);
+                return;
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional real inverse FFT.
+
+        Algorithm has O(N*logN) complexity for any N (composite or prime).
+
+        INPUT PARAMETERS
+            F   -   array[0..floor(N/2)] - frequencies from forward real FFT
+            N   -   problem size
+
+        OUTPUT PARAMETERS
+            A   -   inverse DFT of a input array, array[0..N-1]
+
+        NOTE:
+            F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just  one
+        half of frequencies array is needed - elements from 0 to floor(N/2).  F[0]
+        is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd,  then
+        F[floor(N/2)] has no special properties.
+
+        Relying on properties noted above, FFTR1DInv subroutine uses only elements
+        from 0th to floor(N/2)-th. It ignores imaginary part of F[0],  and in case
+        N is even it ignores imaginary part of F[floor(N/2)] too.  So you can pass
+        either frequencies array with N elements or reduced array with roughly N/2
+        elements - subroutine will successfully transform both.
+
+
+          -- ALGLIB --
+             Copyright 01.06.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fftr1dinv(ref AP.Complex[] f,
+            int n,
+            ref double[] a)
+        {
+            int i = 0;
+            double[] h = new double[0];
+            AP.Complex[] fh = new AP.Complex[0];
+
+            System.Diagnostics.Debug.Assert(n>0, "FFTR1DInv: incorrect N!");
+            
+            //
+            // Special case: N=1, FFT is just identity transform.
+            // After this block we assume that N is strictly greater than 1.
+            //
+            if( n==1 )
+            {
+                a = new double[1];
+                a[0] = f[0].x;
+                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 :)
+            //
+            h = new double[n];
+            a = new double[n];
+            h[0] = f[0].x;
+            for(i=1; i<=(int)Math.Floor((double)(n)/(double)(2))-1; i++)
+            {
+                h[i] = f[i].x-f[i].y;
+                h[n-i] = f[i].x+f[i].y;
+            }
+            if( n%2==0 )
+            {
+                h[(int)Math.Floor((double)(n)/(double)(2))] = f[(int)Math.Floor((double)(n)/(double)(2))].x;
+            }
+            else
+            {
+                h[(int)Math.Floor((double)(n)/(double)(2))] = f[(int)Math.Floor((double)(n)/(double)(2))].x-f[(int)Math.Floor((double)(n)/(double)(2))].y;
+                h[(int)Math.Floor((double)(n)/(double)(2))+1] = f[(int)Math.Floor((double)(n)/(double)(2))].x+f[(int)Math.Floor((double)(n)/(double)(2))].y;
+            }
+            fftr1d(ref h, n, ref fh);
+            for(i=0; i<=n-1; i++)
+            {
+                a[i] = (fh[i].x-fh[i].y)/n;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Never call it directly!
+
+
+          -- ALGLIB --
+             Copyright 01.06.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fftr1dinternaleven(ref double[] a,
+            int n,
+            ref double[] buf,
+            ref ftbase.ftplan plan)
+        {
+            double x = 0;
+            double y = 0;
+            int i = 0;
+            int n2 = 0;
+            int idx = 0;
+            AP.Complex hn = 0;
+            AP.Complex hmnc = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & n%2==0, "FFTR1DEvenInplace: incorrect N!");
+            
+            //
+            // Special cases:
+            // * N=2
+            //
+            // After this block we assume that N is strictly greater than 2
+            //
+            if( n==2 )
+            {
+                x = a[0]+a[1];
+                y = a[0]-a[1];
+                a[0] = x;
+                a[1] = y;
+                return;
+            }
+            
+            //
+            // even-size real FFT, use reduction to the complex task
+            //
+            n2 = n/2;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                buf[i_] = a[i_];
+            }
+            ftbase.ftbaseexecuteplan(ref buf, 0, n2, ref plan);
+            a[0] = buf[0]+buf[1];
+            for(i=1; i<=n2-1; i++)
+            {
+                idx = 2*(i%n2);
+                hn.x = buf[idx+0];
+                hn.y = buf[idx+1];
+                idx = 2*(n2-i);
+                hmnc.x = buf[idx+0];
+                hmnc.y = -buf[idx+1];
+                v.x = -Math.Sin(-(2*Math.PI*i/n));
+                v.y = Math.Cos(-(2*Math.PI*i/n));
+                v = hn+hmnc-v*(hn-hmnc);
+                a[2*i+0] = 0.5*v.x;
+                a[2*i+1] = 0.5*v.y;
+            }
+            a[1] = buf[0]-buf[1];
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Never call it directly!
+
+
+          -- ALGLIB --
+             Copyright 01.06.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fftr1dinvinternaleven(ref double[] a,
+            int n,
+            ref double[] buf,
+            ref ftbase.ftplan plan)
+        {
+            double x = 0;
+            double y = 0;
+            double t = 0;
+            int i = 0;
+            int n2 = 0;
+
+            System.Diagnostics.Debug.Assert(n>0 & n%2==0, "FFTR1DInvInternalEven: incorrect N!");
+            
+            //
+            // Special cases:
+            // * N=2
+            //
+            // After this block we assume that N is strictly greater than 2
+            //
+            if( n==2 )
+            {
+                x = 0.5*(a[0]+a[1]);
+                y = 0.5*(a[0]-a[1]);
+                a[0] = x;
+                a[1] = y;
+                return;
+            }
+            
+            //
+            // inverse real FFT is reduced to the inverse real FHT,
+            // which is reduced to the forward real FHT,
+            // which is reduced to the forward real FFT.
+            //
+            // Don't worry, it is really compact and efficient reduction :)
+            //
+            n2 = n/2;
+            buf[0] = a[0];
+            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];
+            fftr1dinternaleven(ref buf, n, ref a, ref plan);
+            a[0] = buf[0]/n;
+            t = (double)(1)/(double)(n);
+            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);
+            }
+            a[n2] = buf[1]/n;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fht.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fht.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fht.cs	(revision 2645)
@@ -0,0 +1,117 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class fht
+    {
+        /*************************************************************************
+        1-dimensional Fast Hartley Transform.
+
+        Algorithm has O(N*logN) complexity for any N (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..N-1] - real function to be transformed
+            N   -   problem size
+            
+        OUTPUT PARAMETERS
+            A   -   FHT of a input array, array[0..N-1],
+                    A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
+
+
+          -- ALGLIB --
+             Copyright 04.06.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fhtr1d(ref double[] a,
+            int n)
+        {
+            ftbase.ftplan plan = new ftbase.ftplan();
+            int i = 0;
+            AP.Complex[] fa = new AP.Complex[0];
+
+            System.Diagnostics.Debug.Assert(n>0, "FHTR1D: incorrect N!");
+            
+            //
+            // 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
+            //
+            fft.fftr1d(ref a, n, ref fa);
+            for(i=0; i<=n-1; i++)
+            {
+                a[i] = fa[i].x-fa[i].y;
+            }
+        }
+
+
+        /*************************************************************************
+        1-dimensional inverse FHT.
+
+        Algorithm has O(N*logN) complexity for any N (composite or prime).
+
+        INPUT PARAMETERS
+            A   -   array[0..N-1] - complex array to be transformed
+            N   -   problem size
+
+        OUTPUT PARAMETERS
+            A   -   inverse FHT of a input array, array[0..N-1]
+
+
+          -- ALGLIB --
+             Copyright 29.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fhtr1dinv(ref double[] a,
+            int n)
+        {
+            int i = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "FHTR1DInv: incorrect N!");
+            
+            //
+            // 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(ref a, n);
+            for(i=0; i<=n-1; i++)
+            {
+                a[i] = a[i]/n;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fresnel.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fresnel.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/fresnel.cs	(revision 2645)
@@ -0,0 +1,203 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class fresnel
+    {
+        /*************************************************************************
+        Fresnel integral
+
+        Evaluates the Fresnel integrals
+
+                  x
+                  -
+                 | |
+        C(x) =   |   cos(pi/2 t**2) dt,
+               | |
+                -
+                 0
+
+                  x
+                  -
+                 | |
+        S(x) =   |   sin(pi/2 t**2) dt.
+               | |
+                -
+                 0
+
+
+        The integrals are evaluated by a power series for x < 1.
+        For x >= 1 auxiliary functions f(x) and g(x) are employed
+        such that
+
+        C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 )
+        S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 )
+
+
+
+        ACCURACY:
+
+         Relative error.
+
+        Arithmetic  function   domain     # trials      peak         rms
+          IEEE       S(x)      0, 10       10000       2.0e-15     3.2e-16
+          IEEE       C(x)      0, 10       10000       1.8e-15     3.3e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static void fresnelintegral(double x,
+            ref double c,
+            ref double s)
+        {
+            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;
+
+            mpi = 3.14159265358979323846;
+            mpio2 = 1.57079632679489661923;
+            xxa = x;
+            x = Math.Abs(xxa);
+            x2 = x*x;
+            if( (double)(x2)<(double)(2.5625) )
+            {
+                t = x2*x2;
+                sn = -2.99181919401019853726E3;
+                sn = sn*t+7.08840045257738576863E5;
+                sn = sn*t-6.29741486205862506537E7;
+                sn = sn*t+2.54890880573376359104E9;
+                sn = sn*t-4.42979518059697779103E10;
+                sn = sn*t+3.18016297876567817986E11;
+                sd = 1.00000000000000000000E0;
+                sd = sd*t+2.81376268889994315696E2;
+                sd = sd*t+4.55847810806532581675E4;
+                sd = sd*t+5.17343888770096400730E6;
+                sd = sd*t+4.19320245898111231129E8;
+                sd = sd*t+2.24411795645340920940E10;
+                sd = sd*t+6.07366389490084639049E11;
+                cn = -4.98843114573573548651E-8;
+                cn = cn*t+9.50428062829859605134E-6;
+                cn = cn*t-6.45191435683965050962E-4;
+                cn = cn*t+1.88843319396703850064E-2;
+                cn = cn*t-2.05525900955013891793E-1;
+                cn = cn*t+9.99999999999999998822E-1;
+                cd = 3.99982968972495980367E-12;
+                cd = cd*t+9.15439215774657478799E-10;
+                cd = cd*t+1.25001862479598821474E-7;
+                cd = cd*t+1.22262789024179030997E-5;
+                cd = cd*t+8.68029542941784300606E-4;
+                cd = cd*t+4.12142090722199792936E-2;
+                cd = cd*t+1.00000000000000000118E0;
+                s = Math.Sign(xxa)*x*x2*sn/sd;
+                c = Math.Sign(xxa)*x*cn/cd;
+                return;
+            }
+            if( (double)(x)>(double)(36974.0) )
+            {
+                c = Math.Sign(xxa)*0.5;
+                s = Math.Sign(xxa)*0.5;
+                return;
+            }
+            x2 = x*x;
+            t = mpi*x2;
+            u = 1/(t*t);
+            t = 1/t;
+            fn = 4.21543555043677546506E-1;
+            fn = fn*u+1.43407919780758885261E-1;
+            fn = fn*u+1.15220955073585758835E-2;
+            fn = fn*u+3.45017939782574027900E-4;
+            fn = fn*u+4.63613749287867322088E-6;
+            fn = fn*u+3.05568983790257605827E-8;
+            fn = fn*u+1.02304514164907233465E-10;
+            fn = fn*u+1.72010743268161828879E-13;
+            fn = fn*u+1.34283276233062758925E-16;
+            fn = fn*u+3.76329711269987889006E-20;
+            fd = 1.00000000000000000000E0;
+            fd = fd*u+7.51586398353378947175E-1;
+            fd = fd*u+1.16888925859191382142E-1;
+            fd = fd*u+6.44051526508858611005E-3;
+            fd = fd*u+1.55934409164153020873E-4;
+            fd = fd*u+1.84627567348930545870E-6;
+            fd = fd*u+1.12699224763999035261E-8;
+            fd = fd*u+3.60140029589371370404E-11;
+            fd = fd*u+5.88754533621578410010E-14;
+            fd = fd*u+4.52001434074129701496E-17;
+            fd = fd*u+1.25443237090011264384E-20;
+            gn = 5.04442073643383265887E-1;
+            gn = gn*u+1.97102833525523411709E-1;
+            gn = gn*u+1.87648584092575249293E-2;
+            gn = gn*u+6.84079380915393090172E-4;
+            gn = gn*u+1.15138826111884280931E-5;
+            gn = gn*u+9.82852443688422223854E-8;
+            gn = gn*u+4.45344415861750144738E-10;
+            gn = gn*u+1.08268041139020870318E-12;
+            gn = gn*u+1.37555460633261799868E-15;
+            gn = gn*u+8.36354435630677421531E-19;
+            gn = gn*u+1.86958710162783235106E-22;
+            gd = 1.00000000000000000000E0;
+            gd = gd*u+1.47495759925128324529E0;
+            gd = gd*u+3.37748989120019970451E-1;
+            gd = gd*u+2.53603741420338795122E-2;
+            gd = gd*u+8.14679107184306179049E-4;
+            gd = gd*u+1.27545075667729118702E-5;
+            gd = gd*u+1.04314589657571990585E-7;
+            gd = gd*u+4.60680728146520428211E-10;
+            gd = gd*u+1.10273215066240270757E-12;
+            gd = gd*u+1.38796531259578871258E-15;
+            gd = gd*u+8.39158816283118707363E-19;
+            gd = gd*u+1.86958710162783236342E-22;
+            f = 1-u*fn/fd;
+            g = t*gn/gd;
+            t = mpio2*x2;
+            cc = Math.Cos(t);
+            ss = Math.Sin(t);
+            t = mpi*x;
+            c = 0.5+(f*ss-g*cc)/t;
+            s = 0.5-(f*cc+g*ss)/t;
+            c = c*Math.Sign(xxa);
+            s = s*Math.Sign(xxa);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ftbase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ftbase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ftbase.cs	(revision 2645)
@@ -0,0 +1,1625 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ftbase
+    {
+        public struct ftplan
+        {
+            public int[] plan;
+            public double[] precomputed;
+            public double[] tmpbuf;
+            public double[] stackbuf;
+        };
+
+
+
+
+        public const int ftbaseplanentrysize = 8;
+        public const int ftbasecffttask = 0;
+        public const int ftbaserfhttask = 1;
+        public const int ftbaserffttask = 2;
+        public const int fftcooleytukeyplan = 0;
+        public const int fftbluesteinplan = 1;
+        public const int fftcodeletplan = 2;
+        public const int fhtcooleytukeyplan = 3;
+        public const int fhtcodeletplan = 4;
+        public const int fftrealcooleytukeyplan = 5;
+        public const int fftemptyplan = 6;
+        public const int fhtn2plan = 999;
+        public const int ftbaseupdatetw = 4;
+        public const int ftbasecodeletmax = 5;
+        public const int ftbasecodeletrecommended = 5;
+        public const double ftbaseinefficiencyfactor = 1.3;
+        public const int 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
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void ftbasegeneratecomplexfftplan(int n,
+            ref ftplan plan)
+        {
+            int planarraysize = 0;
+            int plansize = 0;
+            int precomputedsize = 0;
+            int tmpmemsize = 0;
+            int stackmemsize = 0;
+            int stackptr = 0;
+
+            planarraysize = 1;
+            plansize = 0;
+            precomputedsize = 0;
+            stackmemsize = 0;
+            stackptr = 0;
+            tmpmemsize = 2*n;
+            plan.plan = new int[planarraysize];
+            ftbasegenerateplanrec(n, ftbasecffttask, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+            System.Diagnostics.Debug.Assert(stackptr==0, "Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!");
+            plan.stackbuf = new double[Math.Max(stackmemsize, 1)];
+            plan.tmpbuf = new double[Math.Max(tmpmemsize, 1)];
+            plan.precomputed = new double[Math.Max(precomputedsize, 1)];
+            stackptr = 0;
+            ftbaseprecomputeplanrec(ref plan, 0, stackptr);
+            System.Diagnostics.Debug.Assert(stackptr==0, "Internal error in FTBaseGenerateComplexFFTPlan: stack ptr!");
+        }
+
+
+        /*************************************************************************
+        Generates real FFT plan
+        *************************************************************************/
+        public static void ftbasegeneraterealfftplan(int n,
+            ref ftplan plan)
+        {
+            int planarraysize = 0;
+            int plansize = 0;
+            int precomputedsize = 0;
+            int tmpmemsize = 0;
+            int stackmemsize = 0;
+            int stackptr = 0;
+
+            planarraysize = 1;
+            plansize = 0;
+            precomputedsize = 0;
+            stackmemsize = 0;
+            stackptr = 0;
+            tmpmemsize = 2*n;
+            plan.plan = new int[planarraysize];
+            ftbasegenerateplanrec(n, ftbaserffttask, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+            System.Diagnostics.Debug.Assert(stackptr==0, "Internal error in FTBaseGenerateRealFFTPlan: stack ptr!");
+            plan.stackbuf = new double[Math.Max(stackmemsize, 1)];
+            plan.tmpbuf = new double[Math.Max(tmpmemsize, 1)];
+            plan.precomputed = new double[Math.Max(precomputedsize, 1)];
+            stackptr = 0;
+            ftbaseprecomputeplanrec(ref plan, 0, stackptr);
+            System.Diagnostics.Debug.Assert(stackptr==0, "Internal error in FTBaseGenerateRealFFTPlan: stack ptr!");
+        }
+
+
+        /*************************************************************************
+        Generates real FHT plan
+        *************************************************************************/
+        public static void ftbasegeneraterealfhtplan(int n,
+            ref ftplan plan)
+        {
+            int planarraysize = 0;
+            int plansize = 0;
+            int precomputedsize = 0;
+            int tmpmemsize = 0;
+            int stackmemsize = 0;
+            int stackptr = 0;
+
+            planarraysize = 1;
+            plansize = 0;
+            precomputedsize = 0;
+            stackmemsize = 0;
+            stackptr = 0;
+            tmpmemsize = n;
+            plan.plan = new int[planarraysize];
+            ftbasegenerateplanrec(n, ftbaserfhttask, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+            System.Diagnostics.Debug.Assert(stackptr==0, "Internal error in FTBaseGenerateRealFHTPlan: stack ptr!");
+            plan.stackbuf = new double[Math.Max(stackmemsize, 1)];
+            plan.tmpbuf = new double[Math.Max(tmpmemsize, 1)];
+            plan.precomputed = new double[Math.Max(precomputedsize, 1)];
+            stackptr = 0;
+            ftbaseprecomputeplanrec(ref plan, 0, stackptr);
+            System.Diagnostics.Debug.Assert(stackptr==0, "Internal error in FTBaseGenerateRealFHTPlan: stack ptr!");
+        }
+
+
+        /*************************************************************************
+        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
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void ftbaseexecuteplan(ref double[] a,
+            int aoffset,
+            int n,
+            ref ftplan plan)
+        {
+            int stackptr = 0;
+
+            stackptr = 0;
+            ftbaseexecuteplanrec(ref a, aoffset, ref 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)
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void ftbaseexecuteplanrec(ref double[] a,
+            int aoffset,
+            ref ftplan plan,
+            int entryoffset,
+            int stackptr)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int idx = 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 v = 0;
+            double[] emptyarray = new double[0];
+            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 a4x = 0;
+            double a4y = 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 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( plan.plan[entryoffset+3]==fftemptyplan )
+            {
+                return;
+            }
+            if( plan.plan[entryoffset+3]==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.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                internalcomplexlintranspose(ref a, n1, n2, aoffset, ref plan.tmpbuf);
+                for(i=0; i<=n2-1; i++)
+                {
+                    ftbaseexecuteplanrec(ref a, aoffset+i*n1*2, ref plan, plan.plan[entryoffset+5], stackptr);
+                }
+                ffttwcalc(ref a, aoffset, n1, n2);
+                internalcomplexlintranspose(ref a, n2, n1, aoffset, ref plan.tmpbuf);
+                for(i=0; i<=n1-1; i++)
+                {
+                    ftbaseexecuteplanrec(ref a, aoffset+i*n2*2, ref plan, plan.plan[entryoffset+6], stackptr);
+                }
+                internalcomplexlintranspose(ref a, n1, n2, aoffset, ref plan.tmpbuf);
+                return;
+            }
+            if( plan.plan[entryoffset+3]==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.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                internalcomplexlintranspose(ref a, n2, n1, aoffset, ref plan.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];
+                    }
+                    ftbaseexecuteplanrec(ref a, offs, ref plan, plan.plan[entryoffset+6], stackptr);
+                    plan.tmpbuf[0] = a[offs+0];
+                    plan.tmpbuf[1] = 0;
+                    plan.tmpbuf[2*n2+0] = a[offs+1];
+                    plan.tmpbuf[2*n2+1] = 0;
+                    for(k=1; k<=n2-1; k++)
+                    {
+                        offs1 = 2*k;
+                        offs2 = 2*n2+2*k;
+                        hk = a[offs+2*k+0];
+                        hnk = a[offs+2*(n2-k)+0];
+                        plan.tmpbuf[offs1+0] = +(0.5*(hk+hnk));
+                        plan.tmpbuf[offs2+1] = -(0.5*(hk-hnk));
+                        hk = a[offs+2*k+1];
+                        hnk = a[offs+2*(n2-k)+1];
+                        plan.tmpbuf[offs2+0] = +(0.5*(hk+hnk));
+                        plan.tmpbuf[offs1+1] = +(0.5*(hk-hnk));
+                    }
+                    i1_ = (0) - (offs);
+                    for(i_=offs; i_<=offs+2*n2*2-1;i_++)
+                    {
+                        a[i_] = plan.tmpbuf[i_+i1_];
+                    }
+                }
+                if( n1%2!=0 )
+                {
+                    ftbaseexecuteplanrec(ref a, aoffset+(n1-1)*n2*2, ref plan, plan.plan[entryoffset+6], stackptr);
+                }
+                ffttwcalc(ref a, aoffset, n2, n1);
+                internalcomplexlintranspose(ref a, n1, n2, aoffset, ref plan.tmpbuf);
+                for(i=0; i<=n2-1; i++)
+                {
+                    ftbaseexecuteplanrec(ref a, aoffset+i*n1*2, ref plan, plan.plan[entryoffset+5], stackptr);
+                }
+                internalcomplexlintranspose(ref a, n2, n1, aoffset, ref plan.tmpbuf);
+                return;
+            }
+            if( plan.plan[entryoffset+3]==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.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                n = n1*n2;
+                internalreallintranspose(ref a, n1, n2, aoffset, ref plan.tmpbuf);
+                for(i=0; i<=n2-1; i++)
+                {
+                    ftbaseexecuteplanrec(ref a, aoffset+i*n1, ref plan, plan.plan[entryoffset+5], stackptr);
+                }
+                for(i=0; i<=n2-1; i++)
+                {
+                    for(j=0; j<=n1-1; j++)
+                    {
+                        offsa = aoffset+i*n1;
+                        hk = a[offsa+j];
+                        hnk = a[offsa+(n1-j)%n1];
+                        offs = 2*(i*n1+j);
+                        plan.tmpbuf[offs+0] = -(0.5*(hnk-hk));
+                        plan.tmpbuf[offs+1] = +(0.5*(hk+hnk));
+                    }
+                }
+                ffttwcalc(ref plan.tmpbuf, 0, n1, n2);
+                for(j=0; j<=n1-1; j++)
+                {
+                    a[aoffset+j] = plan.tmpbuf[2*j+0]+plan.tmpbuf[2*j+1];
+                }
+                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.tmpbuf[offs+2*j+0]+plan.tmpbuf[offs+2*j+1];
+                    }
+                }
+                for(i=1; i<=(n2+1)/2-1; i++)
+                {
+                    offs = 2*i*n1;
+                    offs2 = 2*(n2-i)*n1;
+                    offsa = aoffset+i*n1;
+                    for(j=0; j<=n1-1; j++)
+                    {
+                        a[offsa+j] = plan.tmpbuf[offs+2*j+1]+plan.tmpbuf[offs2+2*j+0];
+                    }
+                    offsa = aoffset+(n2-i)*n1;
+                    for(j=0; j<=n1-1; j++)
+                    {
+                        a[offsa+j] = plan.tmpbuf[offs+2*j+0]+plan.tmpbuf[offs2+2*j+1];
+                    }
+                }
+                internalreallintranspose(ref a, n2, n1, aoffset, ref plan.tmpbuf);
+                for(i=0; i<=n1-1; i++)
+                {
+                    ftbaseexecuteplanrec(ref a, aoffset+i*n2, ref plan, plan.plan[entryoffset+6], stackptr);
+                }
+                internalreallintranspose(ref a, n1, n2, aoffset, ref plan.tmpbuf);
+                return;
+            }
+            if( plan.plan[entryoffset+3]==fhtn2plan )
+            {
+                
+                //
+                // Cooley-Tukey FHT plan
+                //
+                n1 = plan.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                n = n1*n2;
+                reffht(ref a, n, aoffset);
+                return;
+            }
+            if( plan.plan[entryoffset+3]==fftcodeletplan )
+            {
+                n1 = plan.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                n = n1*n2;
+                if( n==2 )
+                {
+                    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;
+                    return;
+                }
+                if( n==3 )
+                {
+                    offs = plan.plan[entryoffset+7];
+                    c1 = plan.precomputed[offs+0];
+                    c2 = plan.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;
+                    return;
+                }
+                if( n==4 )
+                {
+                    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;
+                    return;
+                }
+                if( n==5 )
+                {
+                    offs = plan.plan[entryoffset+7];
+                    c1 = plan.precomputed[offs+0];
+                    c2 = plan.precomputed[offs+1];
+                    c3 = plan.precomputed[offs+2];
+                    c4 = plan.precomputed[offs+3];
+                    c5 = plan.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;
+                    return;
+                }
+            }
+            if( plan.plan[entryoffset+3]==fhtcodeletplan )
+            {
+                n1 = plan.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                n = n1*n2;
+                if( n==2 )
+                {
+                    a0x = a[aoffset+0];
+                    a1x = a[aoffset+1];
+                    a[aoffset+0] = a0x+a1x;
+                    a[aoffset+1] = a0x-a1x;
+                    return;
+                }
+                if( n==3 )
+                {
+                    offs = plan.plan[entryoffset+7];
+                    c1 = plan.precomputed[offs+0];
+                    c2 = plan.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;
+                    return;
+                }
+                if( n==4 )
+                {
+                    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;
+                    return;
+                }
+                if( n==5 )
+                {
+                    offs = plan.plan[entryoffset+7];
+                    c1 = plan.precomputed[offs+0];
+                    c2 = plan.precomputed[offs+1];
+                    c3 = plan.precomputed[offs+2];
+                    c4 = plan.precomputed[offs+3];
+                    c5 = plan.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;
+                    return;
+                }
+            }
+            if( plan.plan[entryoffset+3]==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.plan[entryoffset+1];
+                m = plan.plan[entryoffset+4];
+                offs = plan.plan[entryoffset+7];
+                for(i=stackptr+2*n; i<=stackptr+2*m-1; i++)
+                {
+                    plan.stackbuf[i] = 0;
+                }
+                offsp = offs+2*m;
+                offsa = aoffset;
+                offsb = stackptr;
+                for(i=0; i<=n-1; i++)
+                {
+                    bx = plan.precomputed[offsp+0];
+                    by = plan.precomputed[offsp+1];
+                    x = a[offsa+0];
+                    y = a[offsa+1];
+                    plan.stackbuf[offsb+0] = x*bx-y*-by;
+                    plan.stackbuf[offsb+1] = x*-by+y*bx;
+                    offsp = offsp+2;
+                    offsa = offsa+2;
+                    offsb = offsb+2;
+                }
+                ftbaseexecuteplanrec(ref plan.stackbuf, stackptr, ref plan, plan.plan[entryoffset+5], stackptr+2*2*m);
+                offsb = stackptr;
+                offsp = offs;
+                for(i=0; i<=m-1; i++)
+                {
+                    x = plan.stackbuf[offsb+0];
+                    y = plan.stackbuf[offsb+1];
+                    bx = plan.precomputed[offsp+0];
+                    by = plan.precomputed[offsp+1];
+                    plan.stackbuf[offsb+0] = x*bx-y*by;
+                    plan.stackbuf[offsb+1] = -(x*by+y*bx);
+                    offsb = offsb+2;
+                    offsp = offsp+2;
+                }
+                ftbaseexecuteplanrec(ref plan.stackbuf, stackptr, ref plan, plan.plan[entryoffset+5], stackptr+2*2*m);
+                offsb = stackptr;
+                offsp = offs+2*m;
+                offsa = aoffset;
+                for(i=0; i<=n-1; i++)
+                {
+                    x = +(plan.stackbuf[offsb+0]/m);
+                    y = -(plan.stackbuf[offsb+1]/m);
+                    bx = plan.precomputed[offsp+0];
+                    by = plan.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;
+                }
+                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.
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void ftbasefactorize(int n,
+            int tasktype,
+            ref int n1,
+            ref int n2)
+        {
+            int j = 0;
+
+            n1 = 0;
+            n2 = 0;
+            
+            //
+            // try to find good codelet
+            //
+            if( n1*n2!=n )
+            {
+                for(j=ftbasecodeletrecommended; j>=2; j--)
+                {
+                    if( n%j==0 )
+                    {
+                        n1 = j;
+                        n2 = n/j;
+                        break;
+                    }
+                }
+            }
+            
+            //
+            // try to factorize N
+            //
+            if( n1*n2!=n )
+            {
+                for(j=ftbasecodeletrecommended+1; j<=n-1; j++)
+                {
+                    if( n%j==0 )
+                    {
+                        n1 = j;
+                        n2 = n/j;
+                        break;
+                    }
+                }
+            }
+            
+            //
+            // looks like N is prime :(
+            //
+            if( n1*n2!=n )
+            {
+                n1 = 1;
+                n2 = n;
+            }
+            
+            //
+            // normalize
+            //
+            if( n2==1 & n1!=1 )
+            {
+                n2 = n1;
+                n1 = 1;
+            }
+        }
+
+
+        /*************************************************************************
+        Is number smooth?
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool ftbaseissmooth(int n)
+        {
+            bool result = new bool();
+            int i = 0;
+
+            for(i=2; i<=ftbasemaxsmoothfactor; i++)
+            {
+                while( n%i==0 )
+                {
+                    n = n/i;
+                }
+            }
+            result = n==1;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Returns smallest smooth (divisible only by 2, 3, 5) number that is greater
+        than or equal to max(N,2)
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static int ftbasefindsmooth(int n)
+        {
+            int result = 0;
+            int best = 0;
+
+            best = 2;
+            while( best<n )
+            {
+                best = 2*best;
+            }
+            ftbasefindsmoothrec(n, 1, 2, ref best);
+            result = best;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Returns  smallest  smooth  (divisible only by 2, 3, 5) even number that is
+        greater than or equal to max(N,2)
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static int ftbasefindsmootheven(int n)
+        {
+            int result = 0;
+            int best = 0;
+
+            best = 2;
+            while( best<n )
+            {
+                best = 2*best;
+            }
+            ftbasefindsmoothrec(n, 2, 2, ref best);
+            result = best;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Returns estimate of FLOP count for the FFT.
+
+        It is only an estimate based on operations count for the PERFECT FFT
+        and relative inefficiency of the algorithm actually used.
+
+        N should be power of 2, estimates are badly wrong for non-power-of-2 N's.
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double ftbasegetflopestimate(int n)
+        {
+            double result = 0;
+
+            result = ftbaseinefficiencyfactor*(4*n*Math.Log(n)/Math.Log(2)-6*n+8);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Recurrent subroutine for the FFTGeneratePlan:
+
+        PARAMETERS:
+            N                   plan size
+            IsReal              whether input is real or not.
+                                subroutine MUST NOT ignore this flag because real
+                                inputs comes with non-initialized imaginary parts,
+                                so ignoring this flag will result in corrupted output
+            HalfOut             whether full output or only half of it from 0 to
+                                floor(N/2) is needed. This flag may be ignored if
+                                doing so will simplify calculations
+            Plan                plan array
+            PlanSize            size of used part (in integers)
+            PrecomputedSize     size of precomputed array allocated yet
+            PlanArraySize       plan array size (actual)
+            TmpMemSize          temporary memory required size
+            BluesteinMemSize    temporary memory required size
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void ftbasegenerateplanrec(int n,
+            int tasktype,
+            ref ftplan plan,
+            ref int plansize,
+            ref int precomputedsize,
+            ref int planarraysize,
+            ref int tmpmemsize,
+            ref int stackmemsize,
+            int stackptr)
+        {
+            int j = 0;
+            int k = 0;
+            int m = 0;
+            int n1 = 0;
+            int n2 = 0;
+            int esize = 0;
+            int entryoffset = 0;
+
+            
+            //
+            // prepare
+            //
+            if( plansize+ftbaseplanentrysize>planarraysize )
+            {
+                fftarrayresize(ref plan.plan, ref planarraysize, 8*planarraysize);
+            }
+            entryoffset = plansize;
+            esize = ftbaseplanentrysize;
+            plansize = plansize+esize;
+            
+            //
+            // if N=1, generate empty plan and exit
+            //
+            if( n==1 )
+            {
+                plan.plan[entryoffset+0] = esize;
+                plan.plan[entryoffset+1] = -1;
+                plan.plan[entryoffset+2] = -1;
+                plan.plan[entryoffset+3] = fftemptyplan;
+                plan.plan[entryoffset+4] = -1;
+                plan.plan[entryoffset+5] = -1;
+                plan.plan[entryoffset+6] = -1;
+                plan.plan[entryoffset+7] = -1;
+                return;
+            }
+            
+            //
+            // generate plans
+            //
+            ftbasefactorize(n, tasktype, ref n1, ref n2);
+            if( tasktype==ftbasecffttask | tasktype==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 = Math.Max(tmpmemsize, 2*n1*n2);
+                    plan.plan[entryoffset+0] = esize;
+                    plan.plan[entryoffset+1] = n1;
+                    plan.plan[entryoffset+2] = n2;
+                    if( tasktype==ftbasecffttask )
+                    {
+                        plan.plan[entryoffset+3] = fftcooleytukeyplan;
+                    }
+                    else
+                    {
+                        plan.plan[entryoffset+3] = fftrealcooleytukeyplan;
+                    }
+                    plan.plan[entryoffset+4] = 0;
+                    plan.plan[entryoffset+5] = plansize;
+                    ftbasegenerateplanrec(n1, ftbasecffttask, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+                    plan.plan[entryoffset+6] = plansize;
+                    ftbasegenerateplanrec(n2, ftbasecffttask, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+                    plan.plan[entryoffset+7] = -1;
+                    return;
+                }
+                else
+                {
+                    if( n==2 | n==3 | n==4 | n==5 )
+                    {
+                        
+                        //
+                        // hard-coded plan
+                        //
+                        plan.plan[entryoffset+0] = esize;
+                        plan.plan[entryoffset+1] = n1;
+                        plan.plan[entryoffset+2] = n2;
+                        plan.plan[entryoffset+3] = fftcodeletplan;
+                        plan.plan[entryoffset+4] = 0;
+                        plan.plan[entryoffset+5] = -1;
+                        plan.plan[entryoffset+6] = -1;
+                        plan.plan[entryoffset+7] = precomputedsize;
+                        if( n==3 )
+                        {
+                            precomputedsize = precomputedsize+2;
+                        }
+                        if( n==5 )
+                        {
+                            precomputedsize = precomputedsize+5;
+                        }
+                        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 = Math.Max(tmpmemsize, 2*m);
+                        plan.plan[entryoffset+0] = esize;
+                        plan.plan[entryoffset+1] = n2;
+                        plan.plan[entryoffset+2] = -1;
+                        plan.plan[entryoffset+3] = fftbluesteinplan;
+                        plan.plan[entryoffset+4] = m;
+                        plan.plan[entryoffset+5] = plansize;
+                        stackptr = stackptr+2*2*m;
+                        stackmemsize = Math.Max(stackmemsize, stackptr);
+                        ftbasegenerateplanrec(m, ftbasecffttask, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+                        stackptr = stackptr-2*2*m;
+                        plan.plan[entryoffset+6] = -1;
+                        plan.plan[entryoffset+7] = precomputedsize;
+                        precomputedsize = precomputedsize+2*m+2*n;
+                        return;
+                    }
+                }
+            }
+            if( tasktype==ftbaserfhttask )
+            {
+                
+                //
+                // real FHT plans
+                //
+                if( n1!=1 )
+                {
+                    
+                    //
+                    // Cooley-Tukey plan
+                    //
+                    //
+                    tmpmemsize = Math.Max(tmpmemsize, 2*n1*n2);
+                    plan.plan[entryoffset+0] = esize;
+                    plan.plan[entryoffset+1] = n1;
+                    plan.plan[entryoffset+2] = n2;
+                    plan.plan[entryoffset+3] = fhtcooleytukeyplan;
+                    plan.plan[entryoffset+4] = 0;
+                    plan.plan[entryoffset+5] = plansize;
+                    ftbasegenerateplanrec(n1, tasktype, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+                    plan.plan[entryoffset+6] = plansize;
+                    ftbasegenerateplanrec(n2, tasktype, ref plan, ref plansize, ref precomputedsize, ref planarraysize, ref tmpmemsize, ref stackmemsize, stackptr);
+                    plan.plan[entryoffset+7] = -1;
+                    return;
+                }
+                else
+                {
+                    
+                    //
+                    // N2 plan
+                    //
+                    plan.plan[entryoffset+0] = esize;
+                    plan.plan[entryoffset+1] = n1;
+                    plan.plan[entryoffset+2] = n2;
+                    plan.plan[entryoffset+3] = fhtn2plan;
+                    plan.plan[entryoffset+4] = 0;
+                    plan.plan[entryoffset+5] = -1;
+                    plan.plan[entryoffset+6] = -1;
+                    plan.plan[entryoffset+7] = -1;
+                    if( n==2 | n==3 | n==4 | n==5 )
+                    {
+                        
+                        //
+                        // hard-coded plan
+                        //
+                        plan.plan[entryoffset+0] = esize;
+                        plan.plan[entryoffset+1] = n1;
+                        plan.plan[entryoffset+2] = n2;
+                        plan.plan[entryoffset+3] = fhtcodeletplan;
+                        plan.plan[entryoffset+4] = 0;
+                        plan.plan[entryoffset+5] = -1;
+                        plan.plan[entryoffset+6] = -1;
+                        plan.plan[entryoffset+7] = precomputedsize;
+                        if( n==3 )
+                        {
+                            precomputedsize = precomputedsize+2;
+                        }
+                        if( n==5 )
+                        {
+                            precomputedsize = precomputedsize+5;
+                        }
+                        return;
+                    }
+                    return;
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Recurrent subroutine for precomputing FFT plans
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void ftbaseprecomputeplanrec(ref ftplan plan,
+            int entryoffset,
+            int stackptr)
+        {
+            int i = 0;
+            int j = 0;
+            int idx = 0;
+            int n1 = 0;
+            int n2 = 0;
+            int n = 0;
+            int m = 0;
+            int offs = 0;
+            double v = 0;
+            double[] emptyarray = new double[0];
+            double bx = 0;
+            double by = 0;
+
+            if( plan.plan[entryoffset+3]==fftcooleytukeyplan | plan.plan[entryoffset+3]==fftrealcooleytukeyplan | plan.plan[entryoffset+3]==fhtcooleytukeyplan )
+            {
+                ftbaseprecomputeplanrec(ref plan, plan.plan[entryoffset+5], stackptr);
+                ftbaseprecomputeplanrec(ref plan, plan.plan[entryoffset+6], stackptr);
+                return;
+            }
+            if( plan.plan[entryoffset+3]==fftcodeletplan | plan.plan[entryoffset+3]==fhtcodeletplan )
+            {
+                n1 = plan.plan[entryoffset+1];
+                n2 = plan.plan[entryoffset+2];
+                n = n1*n2;
+                if( n==3 )
+                {
+                    offs = plan.plan[entryoffset+7];
+                    plan.precomputed[offs+0] = Math.Cos(2*Math.PI/3)-1;
+                    plan.precomputed[offs+1] = Math.Sin(2*Math.PI/3);
+                    return;
+                }
+                if( n==5 )
+                {
+                    offs = plan.plan[entryoffset+7];
+                    v = 2*Math.PI/5;
+                    plan.precomputed[offs+0] = (Math.Cos(v)+Math.Cos(2*v))/2-1;
+                    plan.precomputed[offs+1] = (Math.Cos(v)-Math.Cos(2*v))/2;
+                    plan.precomputed[offs+2] = -Math.Sin(v);
+                    plan.precomputed[offs+3] = -(Math.Sin(v)+Math.Sin(2*v));
+                    plan.precomputed[offs+4] = Math.Sin(v)-Math.Sin(2*v);
+                    return;
+                }
+            }
+            if( plan.plan[entryoffset+3]==fftbluesteinplan )
+            {
+                ftbaseprecomputeplanrec(ref plan, plan.plan[entryoffset+5], stackptr);
+                n = plan.plan[entryoffset+1];
+                m = plan.plan[entryoffset+4];
+                offs = plan.plan[entryoffset+7];
+                for(i=0; i<=2*m-1; i++)
+                {
+                    plan.precomputed[offs+i] = 0;
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    bx = Math.Cos(Math.PI*AP.Math.Sqr(i)/n);
+                    by = Math.Sin(Math.PI*AP.Math.Sqr(i)/n);
+                    plan.precomputed[offs+2*i+0] = bx;
+                    plan.precomputed[offs+2*i+1] = by;
+                    plan.precomputed[offs+2*m+2*i+0] = bx;
+                    plan.precomputed[offs+2*m+2*i+1] = by;
+                    if( i>0 )
+                    {
+                        plan.precomputed[offs+2*(m-i)+0] = bx;
+                        plan.precomputed[offs+2*(m-i)+1] = by;
+                    }
+                }
+                ftbaseexecuteplanrec(ref plan.precomputed, offs, ref plan, plan.plan[entryoffset+5], stackptr);
+                return;
+            }
+        }
+
+
+        /*************************************************************************
+        Twiddle factors calculation
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void ffttwcalc(ref double[] a,
+            int aoffset,
+            int n1,
+            int n2)
+        {
+            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;
+
+            n = n1*n2;
+            v = -(2*Math.PI/n);
+            twbasexm1 = -(2*AP.Math.Sqr(Math.Sin(0.5*v)));
+            twbasey = Math.Sin(v);
+            twrowxm1 = 0;
+            twrowy = 0;
+            for(i=0; i<=n2-1; i++)
+            {
+                twxm1 = 0;
+                twy = 0;
+                for(j=0; j<=n1-1; j++)
+                {
+                    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( j<n1-1 )
+                    {
+                        if( j%ftbaseupdatetw==0 )
+                        {
+                            v = -(2*Math.PI*i*(j+1)/n);
+                            twxm1 = -(2*AP.Math.Sqr(Math.Sin(0.5*v)));
+                            twy = Math.Sin(v);
+                        }
+                        else
+                        {
+                            tmpx = twrowxm1+twxm1*twrowxm1-twy*twrowy;
+                            tmpy = twrowy+twxm1*twrowy+twy*twrowxm1;
+                            twxm1 = twxm1+tmpx;
+                            twy = twy+tmpy;
+                        }
+                    }
+                }
+                
+                //
+                // update TwRow: TwRow(new) = TwRow(old)*TwBase
+                //
+                if( i<n2-1 )
+                {
+                    if( j%ftbaseupdatetw==0 )
+                    {
+                        v = -(2*Math.PI*(i+1)/n);
+                        twrowxm1 = -(2*AP.Math.Sqr(Math.Sin(0.5*v)));
+                        twrowy = Math.Sin(v);
+                    }
+                    else
+                    {
+                        tmpx = twbasexm1+twrowxm1*twbasexm1-twrowy*twbasey;
+                        tmpy = twbasey+twrowxm1*twbasey+twrowy*twbasexm1;
+                        twrowxm1 = twrowxm1+tmpx;
+                        twrowy = twrowy+tmpy;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Linear transpose: transpose complex matrix stored in 1-dimensional array
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void internalcomplexlintranspose(ref double[] a,
+            int m,
+            int n,
+            int astart,
+            ref double[] buf)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            ffticltrec(ref a, astart, n, ref buf, 0, m, m, n);
+            i1_ = (0) - (astart);
+            for(i_=astart; i_<=astart+2*m*n-1;i_++)
+            {
+                a[i_] = buf[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Linear transpose: transpose real matrix stored in 1-dimensional array
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void internalreallintranspose(ref double[] a,
+            int m,
+            int n,
+            int astart,
+            ref double[] buf)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            fftirltrec(ref a, astart, n, ref buf, 0, m, m, n);
+            i1_ = (0) - (astart);
+            for(i_=astart; i_<=astart+m*n-1;i_++)
+            {
+                a[i_] = buf[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Recurrent subroutine for a InternalComplexLinTranspose
+
+        Write A^T to B, where:
+        * A is m*n complex matrix stored in array A as pairs of real/image values,
+          beginning from AStart position, with AStride stride
+        * B is n*m complex matrix stored in array B as pairs of real/image values,
+          beginning from BStart position, with BStride stride
+        stride is measured in complex numbers, i.e. in real/image pairs.
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void ffticltrec(ref double[] a,
+            int astart,
+            int astride,
+            ref double[] b,
+            int bstart,
+            int bstride,
+            int m,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int idx1 = 0;
+            int idx2 = 0;
+            int m2 = 0;
+            int m1 = 0;
+            int n1 = 0;
+
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            if( Math.Max(m, n)<=8 )
+            {
+                m2 = 2*bstride;
+                for(i=0; i<=m-1; i++)
+                {
+                    idx1 = bstart+2*i;
+                    idx2 = astart+2*i*astride;
+                    for(j=0; j<=n-1; j++)
+                    {
+                        b[idx1+0] = a[idx2+0];
+                        b[idx1+1] = a[idx2+1];
+                        idx1 = idx1+m2;
+                        idx2 = idx2+2;
+                    }
+                }
+                return;
+            }
+            if( n>m )
+            {
+                
+                //
+                // New partition:
+                //
+                // "A^T -> B" becomes "(A1 A2)^T -> ( B1 )
+                //                                  ( B2 )
+                //
+                n1 = n/2;
+                if( n-n1>=8 & n1%8!=0 )
+                {
+                    n1 = n1+(8-n1%8);
+                }
+                System.Diagnostics.Debug.Assert(n-n1>0);
+                ffticltrec(ref a, astart, astride, ref b, bstart, bstride, m, n1);
+                ffticltrec(ref a, astart+2*n1, astride, ref b, bstart+2*n1*bstride, bstride, m, n-n1);
+            }
+            else
+            {
+                
+                //
+                // New partition:
+                //
+                // "A^T -> B" becomes "( A1 )^T -> ( B1 B2 )
+                //                     ( A2 )
+                //
+                m1 = m/2;
+                if( m-m1>=8 & m1%8!=0 )
+                {
+                    m1 = m1+(8-m1%8);
+                }
+                System.Diagnostics.Debug.Assert(m-m1>0);
+                ffticltrec(ref a, astart, astride, ref b, bstart, bstride, m1, n);
+                ffticltrec(ref a, astart+2*m1*astride, astride, ref b, bstart+2*m1, bstride, m-m1, n);
+            }
+        }
+
+
+        /*************************************************************************
+        Recurrent subroutine for a InternalRealLinTranspose
+
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void fftirltrec(ref double[] a,
+            int astart,
+            int astride,
+            ref double[] b,
+            int bstart,
+            int bstride,
+            int m,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int idx1 = 0;
+            int idx2 = 0;
+            int m1 = 0;
+            int n1 = 0;
+
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            if( Math.Max(m, n)<=8 )
+            {
+                for(i=0; i<=m-1; i++)
+                {
+                    idx1 = bstart+i;
+                    idx2 = astart+i*astride;
+                    for(j=0; j<=n-1; j++)
+                    {
+                        b[idx1] = a[idx2];
+                        idx1 = idx1+bstride;
+                        idx2 = idx2+1;
+                    }
+                }
+                return;
+            }
+            if( n>m )
+            {
+                
+                //
+                // New partition:
+                //
+                // "A^T -> B" becomes "(A1 A2)^T -> ( B1 )
+                //                                  ( B2 )
+                //
+                n1 = n/2;
+                if( n-n1>=8 & n1%8!=0 )
+                {
+                    n1 = n1+(8-n1%8);
+                }
+                System.Diagnostics.Debug.Assert(n-n1>0);
+                fftirltrec(ref a, astart, astride, ref b, bstart, bstride, m, n1);
+                fftirltrec(ref a, astart+n1, astride, ref b, bstart+n1*bstride, bstride, m, n-n1);
+            }
+            else
+            {
+                
+                //
+                // New partition:
+                //
+                // "A^T -> B" becomes "( A1 )^T -> ( B1 B2 )
+                //                     ( A2 )
+                //
+                m1 = m/2;
+                if( m-m1>=8 & m1%8!=0 )
+                {
+                    m1 = m1+(8-m1%8);
+                }
+                System.Diagnostics.Debug.Assert(m-m1>0);
+                fftirltrec(ref a, astart, astride, ref b, bstart, bstride, m1, n);
+                fftirltrec(ref a, astart+m1*astride, astride, ref b, bstart+m1, bstride, m-m1, n);
+            }
+        }
+
+
+        /*************************************************************************
+        recurrent subroutine for FFTFindSmoothRec
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void ftbasefindsmoothrec(int n,
+            int seed,
+            int leastfactor,
+            ref int best)
+        {
+            System.Diagnostics.Debug.Assert(ftbasemaxsmoothfactor<=5, "FTBaseFindSmoothRec: internal error!");
+            if( seed>=n )
+            {
+                best = Math.Min(best, seed);
+                return;
+            }
+            if( leastfactor<=2 )
+            {
+                ftbasefindsmoothrec(n, seed*2, 2, ref best);
+            }
+            if( leastfactor<=3 )
+            {
+                ftbasefindsmoothrec(n, seed*3, 3, ref best);
+            }
+            if( leastfactor<=5 )
+            {
+                ftbasefindsmoothrec(n, seed*5, 5, ref best);
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine: array resize
+
+          -- ALGLIB --
+             Copyright 01.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void fftarrayresize(ref int[] a,
+            ref int asize,
+            int newasize)
+        {
+            int[] tmp = new int[0];
+            int i = 0;
+
+            tmp = new int[asize];
+            for(i=0; i<=asize-1; i++)
+            {
+                tmp[i] = a[i];
+            }
+            a = new int[newasize];
+            for(i=0; i<=asize-1; i++)
+            {
+                a[i] = tmp[i];
+            }
+            asize = newasize;
+        }
+
+
+        /*************************************************************************
+        Reference FHT stub
+        *************************************************************************/
+        private static void reffht(ref double[] a,
+            int n,
+            int offs)
+        {
+            double[] buf = new double[0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "RefFHTR1D: incorrect N!");
+            buf = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                v = 0;
+                for(j=0; j<=n-1; j++)
+                {
+                    v = v+a[offs+j]*(Math.Cos(2*Math.PI*i*j/n)+Math.Sin(2*Math.PI*i*j/n));
+                }
+                buf[i] = v;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                a[offs+i] = buf[i];
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gammafunc.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gammafunc.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gammafunc.cs	(revision 2645)
@@ -0,0 +1,327 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class gammafunc
+    {
+        /*************************************************************************
+        Gamma function
+
+        Input parameters:
+            X   -   argument
+
+        Domain:
+            0 < X < 171.6
+            -170 < X < 0, X is not an integer.
+
+        Relative error:
+         arithmetic   domain     # trials      peak         rms
+            IEEE    -170,-33      20000       2.3e-15     3.3e-16
+            IEEE     -33,  33     20000       9.4e-16     2.2e-16
+            IEEE      33, 171.6   20000       2.3e-15     3.2e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+        Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007).
+        *************************************************************************/
+        public static double gamma(double x)
+        {
+            double result = 0;
+            double p = 0;
+            double pp = 0;
+            double q = 0;
+            double qq = 0;
+            double z = 0;
+            int i = 0;
+            double sgngam = 0;
+
+            sgngam = 1;
+            q = Math.Abs(x);
+            if( (double)(q)>(double)(33.0) )
+            {
+                if( (double)(x)<(double)(0.0) )
+                {
+                    p = (int)Math.Floor(q);
+                    i = (int)Math.Round(p);
+                    if( i%2==0 )
+                    {
+                        sgngam = -1;
+                    }
+                    z = q-p;
+                    if( (double)(z)>(double)(0.5) )
+                    {
+                        p = p+1;
+                        z = q-p;
+                    }
+                    z = q*Math.Sin(Math.PI*z);
+                    z = Math.Abs(z);
+                    z = Math.PI/(z*gammastirf(q));
+                }
+                else
+                {
+                    z = gammastirf(x);
+                }
+                result = sgngam*z;
+                return result;
+            }
+            z = 1;
+            while( (double)(x)>=(double)(3) )
+            {
+                x = x-1;
+                z = z*x;
+            }
+            while( (double)(x)<(double)(0) )
+            {
+                if( (double)(x)>(double)(-0.000000001) )
+                {
+                    result = z/((1+0.5772156649015329*x)*x);
+                    return result;
+                }
+                z = z/x;
+                x = x+1;
+            }
+            while( (double)(x)<(double)(2) )
+            {
+                if( (double)(x)<(double)(0.000000001) )
+                {
+                    result = z/((1+0.5772156649015329*x)*x);
+                    return result;
+                }
+                z = z/x;
+                x = x+1.0;
+            }
+            if( (double)(x)==(double)(2) )
+            {
+                result = z;
+                return result;
+            }
+            x = x-2.0;
+            pp = 1.60119522476751861407E-4;
+            pp = 1.19135147006586384913E-3+x*pp;
+            pp = 1.04213797561761569935E-2+x*pp;
+            pp = 4.76367800457137231464E-2+x*pp;
+            pp = 2.07448227648435975150E-1+x*pp;
+            pp = 4.94214826801497100753E-1+x*pp;
+            pp = 9.99999999999999996796E-1+x*pp;
+            qq = -2.31581873324120129819E-5;
+            qq = 5.39605580493303397842E-4+x*qq;
+            qq = -4.45641913851797240494E-3+x*qq;
+            qq = 1.18139785222060435552E-2+x*qq;
+            qq = 3.58236398605498653373E-2+x*qq;
+            qq = -2.34591795718243348568E-1+x*qq;
+            qq = 7.14304917030273074085E-2+x*qq;
+            qq = 1.00000000000000000320+x*qq;
+            result = z*pp/qq;
+            return result;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Natural logarithm of gamma function
+
+        Input parameters:
+            X       -   argument
+
+        Result:
+            logarithm of the absolute value of the Gamma(X).
+
+        Output parameters:
+            SgnGam  -   sign(Gamma(X))
+
+        Domain:
+            0 < X < 2.55e305
+            -2.55e305 < X < 0, X is not an integer.
+
+        ACCURACY:
+        arithmetic      domain        # trials     peak         rms
+           IEEE    0, 3                 28000     5.4e-16     1.1e-16
+           IEEE    2.718, 2.556e305     40000     3.5e-16     8.3e-17
+        The error criterion was relative when the function magnitude
+        was greater than one but absolute when it was less than one.
+
+        The following test used the relative error criterion, though
+        at certain points the relative error could be much higher than
+        indicated.
+           IEEE    -200, -4             10000     4.8e-16     1.3e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+        Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007).
+        *************************************************************************/
+        public static double lngamma(double x,
+            ref double sgngam)
+        {
+            double result = 0;
+            double a = 0;
+            double b = 0;
+            double c = 0;
+            double p = 0;
+            double q = 0;
+            double u = 0;
+            double w = 0;
+            double z = 0;
+            int i = 0;
+            double logpi = 0;
+            double ls2pi = 0;
+            double tmp = 0;
+
+            sgngam = 1;
+            logpi = 1.14472988584940017414;
+            ls2pi = 0.91893853320467274178;
+            if( (double)(x)<(double)(-34.0) )
+            {
+                q = -x;
+                w = lngamma(q, ref tmp);
+                p = (int)Math.Floor(q);
+                i = (int)Math.Round(p);
+                if( i%2==0 )
+                {
+                    sgngam = -1;
+                }
+                else
+                {
+                    sgngam = 1;
+                }
+                z = q-p;
+                if( (double)(z)>(double)(0.5) )
+                {
+                    p = p+1;
+                    z = p-q;
+                }
+                z = q*Math.Sin(Math.PI*z);
+                result = logpi-Math.Log(z)-w;
+                return result;
+            }
+            if( (double)(x)<(double)(13) )
+            {
+                z = 1;
+                p = 0;
+                u = x;
+                while( (double)(u)>=(double)(3) )
+                {
+                    p = p-1;
+                    u = x+p;
+                    z = z*u;
+                }
+                while( (double)(u)<(double)(2) )
+                {
+                    z = z/u;
+                    p = p+1;
+                    u = x+p;
+                }
+                if( (double)(z)<(double)(0) )
+                {
+                    sgngam = -1;
+                    z = -z;
+                }
+                else
+                {
+                    sgngam = 1;
+                }
+                if( (double)(u)==(double)(2) )
+                {
+                    result = Math.Log(z);
+                    return result;
+                }
+                p = p-2;
+                x = x+p;
+                b = -1378.25152569120859100;
+                b = -38801.6315134637840924+x*b;
+                b = -331612.992738871184744+x*b;
+                b = -1162370.97492762307383+x*b;
+                b = -1721737.00820839662146+x*b;
+                b = -853555.664245765465627+x*b;
+                c = 1;
+                c = -351.815701436523470549+x*c;
+                c = -17064.2106651881159223+x*c;
+                c = -220528.590553854454839+x*c;
+                c = -1139334.44367982507207+x*c;
+                c = -2532523.07177582951285+x*c;
+                c = -2018891.41433532773231+x*c;
+                p = x*b/c;
+                result = Math.Log(z)+p;
+                return result;
+            }
+            q = (x-0.5)*Math.Log(x)-x+ls2pi;
+            if( (double)(x)>(double)(100000000) )
+            {
+                result = q;
+                return result;
+            }
+            p = 1/(x*x);
+            if( (double)(x)>=(double)(1000.0) )
+            {
+                q = q+((7.9365079365079365079365*0.0001*p-2.7777777777777777777778*0.001)*p+0.0833333333333333333333)/x;
+            }
+            else
+            {
+                a = 8.11614167470508450300*0.0001;
+                a = -(5.95061904284301438324*0.0001)+p*a;
+                a = 7.93650340457716943945*0.0001+p*a;
+                a = -(2.77777777730099687205*0.001)+p*a;
+                a = 8.33333333333331927722*0.01+p*a;
+                q = q+a/x;
+            }
+            result = q;
+            return result;
+        }
+
+
+        private static double gammastirf(double x)
+        {
+            double result = 0;
+            double y = 0;
+            double w = 0;
+            double v = 0;
+            double stir = 0;
+
+            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 = Math.Exp(x);
+            if( (double)(x)>(double)(143.01608) )
+            {
+                v = Math.Pow(x, 0.5*x-0.25);
+                y = v*(v/y);
+            }
+            else
+            {
+                y = Math.Pow(x, x-0.5)/y;
+            }
+            result = 2.50662827463100050242*y*w;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gkq.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gkq.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gkq.cs	(revision 2645)
@@ -0,0 +1,917 @@
+/*************************************************************************
+Copyright (c) 2005-2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class gkq
+    {
+        /*************************************************************************
+        Computation of nodes and weights of a Gauss-Kronrod quadrature formula
+
+        The algorithm generates the N-point Gauss-Kronrod quadrature formula  with
+        weight  function  given  by  coefficients  alpha  and beta of a recurrence
+        relation which generates a system of orthogonal polynomials:
+
+            P-1(x)   =  0
+            P0(x)    =  1
+            Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)
+
+        and zero moment Mu0
+
+            Mu0 = integral(W(x)dx,a,b)
+
+
+        INPUT PARAMETERS:
+            Alpha          alpha coefficients, array[0..floor(3*K/2)].
+            Beta           beta coefficients,  array[0..ceil(3*K/2)].
+                            Beta[0] is not used and may be arbitrary.
+                            Beta[I]>0.
+            Mu0            zeroth moment of the weight function.
+            N              number of nodes of the Gauss-Kronrod quadrature formula,
+                            N >= 3,
+                            N =  2*K+1.
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -5    no real and positive Gauss-Kronrod formula can
+                                    be created for such a weight function  with  a
+                                    given number of nodes.
+                            * -4    N is too large, task may be ill  conditioned -
+                                    x[i]=x[i+1] found.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -2    Beta[i]<=0
+                            * -1    incorrect N was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes,
+                            in ascending order.
+            WKronrod    -   array[0..N-1] - Kronrod weights
+            WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
+                            corresponding to extended Kronrod nodes).
+
+          -- ALGLIB --
+             Copyright 08.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gkqgeneraterec(double[] alpha,
+            double[] beta,
+            double mu0,
+            int n,
+            ref int info,
+            ref double[] x,
+            ref double[] wkronrod,
+            ref double[] wgauss)
+        {
+            double[] ta = new double[0];
+            int i = 0;
+            int j = 0;
+            double[] t = new double[0];
+            double[] s = new double[0];
+            int wlen = 0;
+            int woffs = 0;
+            double u = 0;
+            int m = 0;
+            int l = 0;
+            int k = 0;
+            double[] xgtmp = new double[0];
+            double[] wgtmp = new double[0];
+            int i_ = 0;
+
+            alpha = (double[])alpha.Clone();
+            beta = (double[])beta.Clone();
+
+            if( n%2!=1 | n<3 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=(int)Math.Ceiling((double)(3*(n/2))/(double)(2)); i++)
+            {
+                if( (double)(beta[i])<=(double)(0) )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // from external conventions about N/Beta/Mu0 to internal
+            //
+            n = n/2;
+            beta[0] = mu0;
+            
+            //
+            // Calculate Gauss nodes/weights, save them for later processing
+            //
+            gq.gqgeneraterec(ref alpha, ref beta, mu0, n, ref info, ref xgtmp, ref wgtmp);
+            if( info<0 )
+            {
+                return;
+            }
+            
+            //
+            // Resize:
+            // * A from 0..floor(3*n/2) to 0..2*n
+            // * B from 0..ceil(3*n/2)  to 0..2*n
+            //
+            ta = new double[(int)Math.Floor((double)(3*n)/(double)(2))+1];
+            for(i_=0; i_<=(int)Math.Floor((double)(3*n)/(double)(2));i_++)
+            {
+                ta[i_] = alpha[i_];
+            }
+            alpha = new double[2*n+1];
+            for(i_=0; i_<=(int)Math.Floor((double)(3*n)/(double)(2));i_++)
+            {
+                alpha[i_] = ta[i_];
+            }
+            for(i=(int)Math.Floor((double)(3*n)/(double)(2))+1; i<=2*n; i++)
+            {
+                alpha[i] = 0;
+            }
+            ta = new double[(int)Math.Ceiling((double)(3*n)/(double)(2))+1];
+            for(i_=0; i_<=(int)Math.Ceiling((double)(3*n)/(double)(2));i_++)
+            {
+                ta[i_] = beta[i_];
+            }
+            beta = new double[2*n+1];
+            for(i_=0; i_<=(int)Math.Ceiling((double)(3*n)/(double)(2));i_++)
+            {
+                beta[i_] = ta[i_];
+            }
+            for(i=(int)Math.Ceiling((double)(3*n)/(double)(2))+1; i<=2*n; i++)
+            {
+                beta[i] = 0;
+            }
+            
+            //
+            // Initialize T, S
+            //
+            wlen = 2+n/2;
+            t = new double[wlen];
+            s = new double[wlen];
+            ta = new double[wlen];
+            woffs = 1;
+            for(i=0; i<=wlen-1; i++)
+            {
+                t[i] = 0;
+                s[i] = 0;
+            }
+            
+            //
+            // Algorithm from Dirk P. Laurie, "Calculation of Gauss-Kronrod quadrature rules", 1997.
+            //
+            t[woffs+0] = beta[n+1];
+            for(m=0; m<=n-2; m++)
+            {
+                u = 0;
+                for(k=(m+1)/2; k>=0; k--)
+                {
+                    l = m-k;
+                    u = u+(alpha[k+n+1]-alpha[l])*t[woffs+k]+beta[k+n+1]*s[woffs+k-1]-beta[l]*s[woffs+k];
+                    s[woffs+k] = u;
+                }
+                for(i_=0; i_<=wlen-1;i_++)
+                {
+                    ta[i_] = t[i_];
+                }
+                for(i_=0; i_<=wlen-1;i_++)
+                {
+                    t[i_] = s[i_];
+                }
+                for(i_=0; i_<=wlen-1;i_++)
+                {
+                    s[i_] = ta[i_];
+                }
+            }
+            for(j=n/2; j>=0; j--)
+            {
+                s[woffs+j] = s[woffs+j-1];
+            }
+            for(m=n-1; m<=2*n-3; m++)
+            {
+                u = 0;
+                for(k=m+1-n; k<=(m-1)/2; k++)
+                {
+                    l = m-k;
+                    j = n-1-l;
+                    u = u-(alpha[k+n+1]-alpha[l])*t[woffs+j]-beta[k+n+1]*s[woffs+j]+beta[l]*s[woffs+j+1];
+                    s[woffs+j] = u;
+                }
+                if( m%2==0 )
+                {
+                    k = m/2;
+                    alpha[k+n+1] = alpha[k]+(s[woffs+j]-beta[k+n+1]*s[woffs+j+1])/t[woffs+j+1];
+                }
+                else
+                {
+                    k = (m+1)/2;
+                    beta[k+n+1] = s[woffs+j]/s[woffs+j+1];
+                }
+                for(i_=0; i_<=wlen-1;i_++)
+                {
+                    ta[i_] = t[i_];
+                }
+                for(i_=0; i_<=wlen-1;i_++)
+                {
+                    t[i_] = s[i_];
+                }
+                for(i_=0; i_<=wlen-1;i_++)
+                {
+                    s[i_] = ta[i_];
+                }
+            }
+            alpha[2*n] = alpha[n-1]-beta[2*n]*s[woffs+0]/t[woffs+0];
+            
+            //
+            // calculation of Kronrod nodes and weights, unpacking of Gauss weights
+            //
+            gq.gqgeneraterec(ref alpha, ref beta, mu0, 2*n+1, ref info, ref x, ref wkronrod);
+            if( info==-2 )
+            {
+                info = -5;
+            }
+            if( info<0 )
+            {
+                return;
+            }
+            for(i=0; i<=2*n-1; i++)
+            {
+                if( (double)(x[i])>=(double)(x[i+1]) )
+                {
+                    info = -4;
+                }
+            }
+            if( info<0 )
+            {
+                return;
+            }
+            wgauss = new double[2*n+1];
+            for(i=0; i<=2*n; i++)
+            {
+                wgauss[i] = 0;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                wgauss[2*i+1] = wgtmp[i];
+            }
+        }
+
+
+        /*************************************************************************
+        Returns   Gauss   and   Gauss-Kronrod   nodes/weights  for  Gauss-Legendre
+        quadrature with N points.
+
+        GKQLegendreCalc (calculation) or  GKQLegendreTbl  (precomputed  table)  is
+        used depending on machine precision and number of nodes.
+
+        INPUT PARAMETERS:
+            N           -   number of Kronrod nodes, must be odd number, >=3.
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -4    an  error   was   detected   when  calculating
+                                    weights/nodes.  N  is  too  large   to  obtain
+                                    weights/nodes  with  high   enough   accuracy.
+                                    Try  to   use   multiple   precision  version.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -1    incorrect N was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes, ordered in
+                            ascending order.
+            WKronrod    -   array[0..N-1] - Kronrod weights
+            WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
+                            corresponding to extended Kronrod nodes).
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gkqgenerategausslegendre(int n,
+            ref int info,
+            ref double[] x,
+            ref double[] wkronrod,
+            ref double[] wgauss)
+        {
+            double eps = 0;
+
+            if( (double)(AP.Math.MachineEpsilon)>(double)(1.0E-32) & (n==15 | n==21 | n==31 | n==41 | n==51 | n==61) )
+            {
+                info = 1;
+                gkqlegendretbl(n, ref x, ref wkronrod, ref wgauss, ref eps);
+            }
+            else
+            {
+                gkqlegendrecalc(n, ref info, ref x, ref wkronrod, ref wgauss);
+            }
+        }
+
+
+        /*************************************************************************
+        Returns   Gauss   and   Gauss-Kronrod   nodes/weights   for   Gauss-Jacobi
+        quadrature on [-1,1] with weight function
+
+            W(x)=Power(1-x,Alpha)*Power(1+x,Beta).
+
+        INPUT PARAMETERS:
+            N           -   number of Kronrod nodes, must be odd number, >=3.
+            Alpha       -   power-law coefficient, Alpha>-1
+            Beta        -   power-law coefficient, Beta>-1
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -5    no real and positive Gauss-Kronrod formula can
+                                    be created for such a weight function  with  a
+                                    given number of nodes.
+                            * -4    an  error  was   detected   when   calculating
+                                    weights/nodes. Alpha or  Beta  are  too  close
+                                    to -1 to obtain weights/nodes with high enough
+                                    accuracy, or, may be, N is too large.  Try  to
+                                    use multiple precision version.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -1    incorrect N was passed
+                            * +1    OK
+                            * +2    OK, but quadrature rule have exterior  nodes,
+                                    x[0]<-1 or x[n-1]>+1
+            X           -   array[0..N-1] - array of quadrature nodes, ordered in
+                            ascending order.
+            WKronrod    -   array[0..N-1] - Kronrod weights
+            WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
+                            corresponding to extended Kronrod nodes).
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gkqgenerategaussjacobi(int n,
+            double alpha,
+            double beta,
+            ref int info,
+            ref double[] x,
+            ref double[] wkronrod,
+            ref double[] wgauss)
+        {
+            int clen = 0;
+            double[] a = new double[0];
+            double[] b = new double[0];
+            double alpha2 = 0;
+            double beta2 = 0;
+            double apb = 0;
+            double t = 0;
+            int i = 0;
+            double s = 0;
+
+            if( n%2!=1 | n<3 )
+            {
+                info = -1;
+                return;
+            }
+            if( (double)(alpha)<=(double)(-1) | (double)(beta)<=(double)(-1) )
+            {
+                info = -1;
+                return;
+            }
+            clen = (int)Math.Ceiling((double)(3*(n/2))/(double)(2))+1;
+            a = new double[clen];
+            b = new double[clen];
+            for(i=0; i<=clen-1; i++)
+            {
+                a[i] = 0;
+            }
+            apb = alpha+beta;
+            a[0] = (beta-alpha)/(apb+2);
+            t = (apb+1)*Math.Log(2)+gammafunc.lngamma(alpha+1, ref s)+gammafunc.lngamma(beta+1, ref s)-gammafunc.lngamma(apb+2, ref s);
+            if( (double)(t)>(double)(Math.Log(AP.Math.MaxRealNumber)) )
+            {
+                info = -4;
+                return;
+            }
+            b[0] = Math.Exp(t);
+            if( clen>1 )
+            {
+                alpha2 = AP.Math.Sqr(alpha);
+                beta2 = AP.Math.Sqr(beta);
+                a[1] = (beta2-alpha2)/((apb+2)*(apb+4));
+                b[1] = 4*(alpha+1)*(beta+1)/((apb+3)*AP.Math.Sqr(apb+2));
+                for(i=2; i<=clen-1; i++)
+                {
+                    a[i] = 0.25*(beta2-alpha2)/(i*i*(1+0.5*apb/i)*(1+0.5*(apb+2)/i));
+                    b[i] = 0.25*(1+alpha/i)*(1+beta/i)*(1+apb/i)/((1+0.5*(apb+1)/i)*(1+0.5*(apb-1)/i)*AP.Math.Sqr(1+0.5*apb/i));
+                }
+            }
+            gkqgeneraterec(a, b, b[0], n, ref info, ref x, ref wkronrod, ref wgauss);
+            
+            //
+            // test basic properties to detect errors
+            //
+            if( info>0 )
+            {
+                if( (double)(x[0])<(double)(-1) | (double)(x[n-1])>(double)(+1) )
+                {
+                    info = 2;
+                }
+                for(i=0; i<=n-2; i++)
+                {
+                    if( (double)(x[i])>=(double)(x[i+1]) )
+                    {
+                        info = -4;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns Gauss and Gauss-Kronrod nodes for quadrature with N points.
+
+        Reduction to tridiagonal eigenproblem is used.
+
+        INPUT PARAMETERS:
+            N           -   number of Kronrod nodes, must be odd number, >=3.
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -4    an  error   was   detected   when  calculating
+                                    weights/nodes.  N  is  too  large   to  obtain
+                                    weights/nodes  with  high   enough   accuracy.
+                                    Try  to   use   multiple   precision  version.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -1    incorrect N was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes, ordered in
+                            ascending order.
+            WKronrod    -   array[0..N-1] - Kronrod weights
+            WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
+                            corresponding to extended Kronrod nodes).
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gkqlegendrecalc(int n,
+            ref int info,
+            ref double[] x,
+            ref double[] wkronrod,
+            ref double[] wgauss)
+        {
+            double[] alpha = new double[0];
+            double[] beta = new double[0];
+            int alen = 0;
+            int blen = 0;
+            double mu0 = 0;
+            int k = 0;
+            int i = 0;
+
+            if( n%2!=1 | n<3 )
+            {
+                info = -1;
+                return;
+            }
+            mu0 = 2;
+            alen = (int)Math.Floor((double)(3*(n/2))/(double)(2))+1;
+            blen = (int)Math.Ceiling((double)(3*(n/2))/(double)(2))+1;
+            alpha = new double[alen];
+            beta = new double[blen];
+            for(k=0; k<=alen-1; k++)
+            {
+                alpha[k] = 0;
+            }
+            beta[0] = 2;
+            for(k=1; k<=blen-1; k++)
+            {
+                beta[k] = 1/(4-1/AP.Math.Sqr(k));
+            }
+            gkqgeneraterec(alpha, beta, mu0, n, ref info, ref x, ref wkronrod, ref wgauss);
+            
+            //
+            // test basic properties to detect errors
+            //
+            if( info>0 )
+            {
+                if( (double)(x[0])<(double)(-1) | (double)(x[n-1])>(double)(+1) )
+                {
+                    info = -4;
+                }
+                for(i=0; i<=n-2; i++)
+                {
+                    if( (double)(x[i])>=(double)(x[i+1]) )
+                    {
+                        info = -4;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns Gauss and Gauss-Kronrod nodes for quadrature with N  points  using
+        pre-calculated table. Nodes/weights were  computed  with  accuracy  up  to
+        1.0E-32 (if MPFR version of ALGLIB is used). In standard double  precision
+        accuracy reduces to something about 2.0E-16 (depending  on your compiler's
+        handling of long floating point constants).
+
+        INPUT PARAMETERS:
+            N           -   number of Kronrod nodes.
+                            N can be 15, 21, 31, 41, 51, 61.
+
+        OUTPUT PARAMETERS:
+            X           -   array[0..N-1] - array of quadrature nodes, ordered in
+                            ascending order.
+            WKronrod    -   array[0..N-1] - Kronrod weights
+            WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
+                            corresponding to extended Kronrod nodes).
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gkqlegendretbl(int n,
+            ref double[] x,
+            ref double[] wkronrod,
+            ref double[] wgauss,
+            ref double eps)
+        {
+            int i = 0;
+            int ng = 0;
+            int[] p1 = new int[0];
+            int[] p2 = new int[0];
+            double tmp = 0;
+
+            System.Diagnostics.Debug.Assert(n==15 | n==21 | n==31 | n==41 | n==51 | n==61, "GKQNodesTbl: incorrect N!");
+            x = new double[n-1+1];
+            wkronrod = new double[n-1+1];
+            wgauss = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                x[i] = 0;
+                wkronrod[i] = 0;
+                wgauss[i] = 0;
+            }
+            eps = Math.Max(AP.Math.MachineEpsilon, 1.0E-32);
+            if( n==15 )
+            {
+                ng = 4;
+                wgauss[0] = 0.129484966168869693270611432679082;
+                wgauss[1] = 0.279705391489276667901467771423780;
+                wgauss[2] = 0.381830050505118944950369775488975;
+                wgauss[3] = 0.417959183673469387755102040816327;
+                x[0] = 0.991455371120812639206854697526329;
+                x[1] = 0.949107912342758524526189684047851;
+                x[2] = 0.864864423359769072789712788640926;
+                x[3] = 0.741531185599394439863864773280788;
+                x[4] = 0.586087235467691130294144838258730;
+                x[5] = 0.405845151377397166906606412076961;
+                x[6] = 0.207784955007898467600689403773245;
+                x[7] = 0.000000000000000000000000000000000;
+                wkronrod[0] = 0.022935322010529224963732008058970;
+                wkronrod[1] = 0.063092092629978553290700663189204;
+                wkronrod[2] = 0.104790010322250183839876322541518;
+                wkronrod[3] = 0.140653259715525918745189590510238;
+                wkronrod[4] = 0.169004726639267902826583426598550;
+                wkronrod[5] = 0.190350578064785409913256402421014;
+                wkronrod[6] = 0.204432940075298892414161999234649;
+                wkronrod[7] = 0.209482141084727828012999174891714;
+            }
+            if( n==21 )
+            {
+                ng = 5;
+                wgauss[0] = 0.066671344308688137593568809893332;
+                wgauss[1] = 0.149451349150580593145776339657697;
+                wgauss[2] = 0.219086362515982043995534934228163;
+                wgauss[3] = 0.269266719309996355091226921569469;
+                wgauss[4] = 0.295524224714752870173892994651338;
+                x[0] = 0.995657163025808080735527280689003;
+                x[1] = 0.973906528517171720077964012084452;
+                x[2] = 0.930157491355708226001207180059508;
+                x[3] = 0.865063366688984510732096688423493;
+                x[4] = 0.780817726586416897063717578345042;
+                x[5] = 0.679409568299024406234327365114874;
+                x[6] = 0.562757134668604683339000099272694;
+                x[7] = 0.433395394129247190799265943165784;
+                x[8] = 0.294392862701460198131126603103866;
+                x[9] = 0.148874338981631210884826001129720;
+                x[10] = 0.000000000000000000000000000000000;
+                wkronrod[0] = 0.011694638867371874278064396062192;
+                wkronrod[1] = 0.032558162307964727478818972459390;
+                wkronrod[2] = 0.054755896574351996031381300244580;
+                wkronrod[3] = 0.075039674810919952767043140916190;
+                wkronrod[4] = 0.093125454583697605535065465083366;
+                wkronrod[5] = 0.109387158802297641899210590325805;
+                wkronrod[6] = 0.123491976262065851077958109831074;
+                wkronrod[7] = 0.134709217311473325928054001771707;
+                wkronrod[8] = 0.142775938577060080797094273138717;
+                wkronrod[9] = 0.147739104901338491374841515972068;
+                wkronrod[10] = 0.149445554002916905664936468389821;
+            }
+            if( n==31 )
+            {
+                ng = 8;
+                wgauss[0] = 0.030753241996117268354628393577204;
+                wgauss[1] = 0.070366047488108124709267416450667;
+                wgauss[2] = 0.107159220467171935011869546685869;
+                wgauss[3] = 0.139570677926154314447804794511028;
+                wgauss[4] = 0.166269205816993933553200860481209;
+                wgauss[5] = 0.186161000015562211026800561866423;
+                wgauss[6] = 0.198431485327111576456118326443839;
+                wgauss[7] = 0.202578241925561272880620199967519;
+                x[0] = 0.998002298693397060285172840152271;
+                x[1] = 0.987992518020485428489565718586613;
+                x[2] = 0.967739075679139134257347978784337;
+                x[3] = 0.937273392400705904307758947710209;
+                x[4] = 0.897264532344081900882509656454496;
+                x[5] = 0.848206583410427216200648320774217;
+                x[6] = 0.790418501442465932967649294817947;
+                x[7] = 0.724417731360170047416186054613938;
+                x[8] = 0.650996741297416970533735895313275;
+                x[9] = 0.570972172608538847537226737253911;
+                x[10] = 0.485081863640239680693655740232351;
+                x[11] = 0.394151347077563369897207370981045;
+                x[12] = 0.299180007153168812166780024266389;
+                x[13] = 0.201194093997434522300628303394596;
+                x[14] = 0.101142066918717499027074231447392;
+                x[15] = 0.000000000000000000000000000000000;
+                wkronrod[0] = 0.005377479872923348987792051430128;
+                wkronrod[1] = 0.015007947329316122538374763075807;
+                wkronrod[2] = 0.025460847326715320186874001019653;
+                wkronrod[3] = 0.035346360791375846222037948478360;
+                wkronrod[4] = 0.044589751324764876608227299373280;
+                wkronrod[5] = 0.053481524690928087265343147239430;
+                wkronrod[6] = 0.062009567800670640285139230960803;
+                wkronrod[7] = 0.069854121318728258709520077099147;
+                wkronrod[8] = 0.076849680757720378894432777482659;
+                wkronrod[9] = 0.083080502823133021038289247286104;
+                wkronrod[10] = 0.088564443056211770647275443693774;
+                wkronrod[11] = 0.093126598170825321225486872747346;
+                wkronrod[12] = 0.096642726983623678505179907627589;
+                wkronrod[13] = 0.099173598721791959332393173484603;
+                wkronrod[14] = 0.100769845523875595044946662617570;
+                wkronrod[15] = 0.101330007014791549017374792767493;
+            }
+            if( n==41 )
+            {
+                ng = 10;
+                wgauss[0] = 0.017614007139152118311861962351853;
+                wgauss[1] = 0.040601429800386941331039952274932;
+                wgauss[2] = 0.062672048334109063569506535187042;
+                wgauss[3] = 0.083276741576704748724758143222046;
+                wgauss[4] = 0.101930119817240435036750135480350;
+                wgauss[5] = 0.118194531961518417312377377711382;
+                wgauss[6] = 0.131688638449176626898494499748163;
+                wgauss[7] = 0.142096109318382051329298325067165;
+                wgauss[8] = 0.149172986472603746787828737001969;
+                wgauss[9] = 0.152753387130725850698084331955098;
+                x[0] = 0.998859031588277663838315576545863;
+                x[1] = 0.993128599185094924786122388471320;
+                x[2] = 0.981507877450250259193342994720217;
+                x[3] = 0.963971927277913791267666131197277;
+                x[4] = 0.940822633831754753519982722212443;
+                x[5] = 0.912234428251325905867752441203298;
+                x[6] = 0.878276811252281976077442995113078;
+                x[7] = 0.839116971822218823394529061701521;
+                x[8] = 0.795041428837551198350638833272788;
+                x[9] = 0.746331906460150792614305070355642;
+                x[10] = 0.693237656334751384805490711845932;
+                x[11] = 0.636053680726515025452836696226286;
+                x[12] = 0.575140446819710315342946036586425;
+                x[13] = 0.510867001950827098004364050955251;
+                x[14] = 0.443593175238725103199992213492640;
+                x[15] = 0.373706088715419560672548177024927;
+                x[16] = 0.301627868114913004320555356858592;
+                x[17] = 0.227785851141645078080496195368575;
+                x[18] = 0.152605465240922675505220241022678;
+                x[19] = 0.076526521133497333754640409398838;
+                x[20] = 0.000000000000000000000000000000000;
+                wkronrod[0] = 0.003073583718520531501218293246031;
+                wkronrod[1] = 0.008600269855642942198661787950102;
+                wkronrod[2] = 0.014626169256971252983787960308868;
+                wkronrod[3] = 0.020388373461266523598010231432755;
+                wkronrod[4] = 0.025882133604951158834505067096153;
+                wkronrod[5] = 0.031287306777032798958543119323801;
+                wkronrod[6] = 0.036600169758200798030557240707211;
+                wkronrod[7] = 0.041668873327973686263788305936895;
+                wkronrod[8] = 0.046434821867497674720231880926108;
+                wkronrod[9] = 0.050944573923728691932707670050345;
+                wkronrod[10] = 0.055195105348285994744832372419777;
+                wkronrod[11] = 0.059111400880639572374967220648594;
+                wkronrod[12] = 0.062653237554781168025870122174255;
+                wkronrod[13] = 0.065834597133618422111563556969398;
+                wkronrod[14] = 0.068648672928521619345623411885368;
+                wkronrod[15] = 0.071054423553444068305790361723210;
+                wkronrod[16] = 0.073030690332786667495189417658913;
+                wkronrod[17] = 0.074582875400499188986581418362488;
+                wkronrod[18] = 0.075704497684556674659542775376617;
+                wkronrod[19] = 0.076377867672080736705502835038061;
+                wkronrod[20] = 0.076600711917999656445049901530102;
+            }
+            if( n==51 )
+            {
+                ng = 13;
+                wgauss[0] = 0.011393798501026287947902964113235;
+                wgauss[1] = 0.026354986615032137261901815295299;
+                wgauss[2] = 0.040939156701306312655623487711646;
+                wgauss[3] = 0.054904695975835191925936891540473;
+                wgauss[4] = 0.068038333812356917207187185656708;
+                wgauss[5] = 0.080140700335001018013234959669111;
+                wgauss[6] = 0.091028261982963649811497220702892;
+                wgauss[7] = 0.100535949067050644202206890392686;
+                wgauss[8] = 0.108519624474263653116093957050117;
+                wgauss[9] = 0.114858259145711648339325545869556;
+                wgauss[10] = 0.119455763535784772228178126512901;
+                wgauss[11] = 0.122242442990310041688959518945852;
+                wgauss[12] = 0.123176053726715451203902873079050;
+                x[0] = 0.999262104992609834193457486540341;
+                x[1] = 0.995556969790498097908784946893902;
+                x[2] = 0.988035794534077247637331014577406;
+                x[3] = 0.976663921459517511498315386479594;
+                x[4] = 0.961614986425842512418130033660167;
+                x[5] = 0.942974571228974339414011169658471;
+                x[6] = 0.920747115281701561746346084546331;
+                x[7] = 0.894991997878275368851042006782805;
+                x[8] = 0.865847065293275595448996969588340;
+                x[9] = 0.833442628760834001421021108693570;
+                x[10] = 0.797873797998500059410410904994307;
+                x[11] = 0.759259263037357630577282865204361;
+                x[12] = 0.717766406813084388186654079773298;
+                x[13] = 0.673566368473468364485120633247622;
+                x[14] = 0.626810099010317412788122681624518;
+                x[15] = 0.577662930241222967723689841612654;
+                x[16] = 0.526325284334719182599623778158010;
+                x[17] = 0.473002731445714960522182115009192;
+                x[18] = 0.417885382193037748851814394594572;
+                x[19] = 0.361172305809387837735821730127641;
+                x[20] = 0.303089538931107830167478909980339;
+                x[21] = 0.243866883720988432045190362797452;
+                x[22] = 0.183718939421048892015969888759528;
+                x[23] = 0.122864692610710396387359818808037;
+                x[24] = 0.061544483005685078886546392366797;
+                x[25] = 0.000000000000000000000000000000000;
+                wkronrod[0] = 0.001987383892330315926507851882843;
+                wkronrod[1] = 0.005561932135356713758040236901066;
+                wkronrod[2] = 0.009473973386174151607207710523655;
+                wkronrod[3] = 0.013236229195571674813656405846976;
+                wkronrod[4] = 0.016847817709128298231516667536336;
+                wkronrod[5] = 0.020435371145882835456568292235939;
+                wkronrod[6] = 0.024009945606953216220092489164881;
+                wkronrod[7] = 0.027475317587851737802948455517811;
+                wkronrod[8] = 0.030792300167387488891109020215229;
+                wkronrod[9] = 0.034002130274329337836748795229551;
+                wkronrod[10] = 0.037116271483415543560330625367620;
+                wkronrod[11] = 0.040083825504032382074839284467076;
+                wkronrod[12] = 0.042872845020170049476895792439495;
+                wkronrod[13] = 0.045502913049921788909870584752660;
+                wkronrod[14] = 0.047982537138836713906392255756915;
+                wkronrod[15] = 0.050277679080715671963325259433440;
+                wkronrod[16] = 0.052362885806407475864366712137873;
+                wkronrod[17] = 0.054251129888545490144543370459876;
+                wkronrod[18] = 0.055950811220412317308240686382747;
+                wkronrod[19] = 0.057437116361567832853582693939506;
+                wkronrod[20] = 0.058689680022394207961974175856788;
+                wkronrod[21] = 0.059720340324174059979099291932562;
+                wkronrod[22] = 0.060539455376045862945360267517565;
+                wkronrod[23] = 0.061128509717053048305859030416293;
+                wkronrod[24] = 0.061471189871425316661544131965264;
+                wkronrod[25] = 0.061580818067832935078759824240055;
+            }
+            if( n==61 )
+            {
+                ng = 15;
+                wgauss[0] = 0.007968192496166605615465883474674;
+                wgauss[1] = 0.018466468311090959142302131912047;
+                wgauss[2] = 0.028784707883323369349719179611292;
+                wgauss[3] = 0.038799192569627049596801936446348;
+                wgauss[4] = 0.048402672830594052902938140422808;
+                wgauss[5] = 0.057493156217619066481721689402056;
+                wgauss[6] = 0.065974229882180495128128515115962;
+                wgauss[7] = 0.073755974737705206268243850022191;
+                wgauss[8] = 0.080755895229420215354694938460530;
+                wgauss[9] = 0.086899787201082979802387530715126;
+                wgauss[10] = 0.092122522237786128717632707087619;
+                wgauss[11] = 0.096368737174644259639468626351810;
+                wgauss[12] = 0.099593420586795267062780282103569;
+                wgauss[13] = 0.101762389748405504596428952168554;
+                wgauss[14] = 0.102852652893558840341285636705415;
+                x[0] = 0.999484410050490637571325895705811;
+                x[1] = 0.996893484074649540271630050918695;
+                x[2] = 0.991630996870404594858628366109486;
+                x[3] = 0.983668123279747209970032581605663;
+                x[4] = 0.973116322501126268374693868423707;
+                x[5] = 0.960021864968307512216871025581798;
+                x[6] = 0.944374444748559979415831324037439;
+                x[7] = 0.926200047429274325879324277080474;
+                x[8] = 0.905573307699907798546522558925958;
+                x[9] = 0.882560535792052681543116462530226;
+                x[10] = 0.857205233546061098958658510658944;
+                x[11] = 0.829565762382768397442898119732502;
+                x[12] = 0.799727835821839083013668942322683;
+                x[13] = 0.767777432104826194917977340974503;
+                x[14] = 0.733790062453226804726171131369528;
+                x[15] = 0.697850494793315796932292388026640;
+                x[16] = 0.660061064126626961370053668149271;
+                x[17] = 0.620526182989242861140477556431189;
+                x[18] = 0.579345235826361691756024932172540;
+                x[19] = 0.536624148142019899264169793311073;
+                x[20] = 0.492480467861778574993693061207709;
+                x[21] = 0.447033769538089176780609900322854;
+                x[22] = 0.400401254830394392535476211542661;
+                x[23] = 0.352704725530878113471037207089374;
+                x[24] = 0.304073202273625077372677107199257;
+                x[25] = 0.254636926167889846439805129817805;
+                x[26] = 0.204525116682309891438957671002025;
+                x[27] = 0.153869913608583546963794672743256;
+                x[28] = 0.102806937966737030147096751318001;
+                x[29] = 0.051471842555317695833025213166723;
+                x[30] = 0.000000000000000000000000000000000;
+                wkronrod[0] = 0.001389013698677007624551591226760;
+                wkronrod[1] = 0.003890461127099884051267201844516;
+                wkronrod[2] = 0.006630703915931292173319826369750;
+                wkronrod[3] = 0.009273279659517763428441146892024;
+                wkronrod[4] = 0.011823015253496341742232898853251;
+                wkronrod[5] = 0.014369729507045804812451432443580;
+                wkronrod[6] = 0.016920889189053272627572289420322;
+                wkronrod[7] = 0.019414141193942381173408951050128;
+                wkronrod[8] = 0.021828035821609192297167485738339;
+                wkronrod[9] = 0.024191162078080601365686370725232;
+                wkronrod[10] = 0.026509954882333101610601709335075;
+                wkronrod[11] = 0.028754048765041292843978785354334;
+                wkronrod[12] = 0.030907257562387762472884252943092;
+                wkronrod[13] = 0.032981447057483726031814191016854;
+                wkronrod[14] = 0.034979338028060024137499670731468;
+                wkronrod[15] = 0.036882364651821229223911065617136;
+                wkronrod[16] = 0.038678945624727592950348651532281;
+                wkronrod[17] = 0.040374538951535959111995279752468;
+                wkronrod[18] = 0.041969810215164246147147541285970;
+                wkronrod[19] = 0.043452539701356069316831728117073;
+                wkronrod[20] = 0.044814800133162663192355551616723;
+                wkronrod[21] = 0.046059238271006988116271735559374;
+                wkronrod[22] = 0.047185546569299153945261478181099;
+                wkronrod[23] = 0.048185861757087129140779492298305;
+                wkronrod[24] = 0.049055434555029778887528165367238;
+                wkronrod[25] = 0.049795683427074206357811569379942;
+                wkronrod[26] = 0.050405921402782346840893085653585;
+                wkronrod[27] = 0.050881795898749606492297473049805;
+                wkronrod[28] = 0.051221547849258772170656282604944;
+                wkronrod[29] = 0.051426128537459025933862879215781;
+                wkronrod[30] = 0.051494729429451567558340433647099;
+            }
+            
+            //
+            // copy nodes
+            //
+            for(i=n-1; i>=n/2; i--)
+            {
+                x[i] = -x[n-1-i];
+            }
+            
+            //
+            // copy Kronrod weights
+            //
+            for(i=n-1; i>=n/2; i--)
+            {
+                wkronrod[i] = wkronrod[n-1-i];
+            }
+            
+            //
+            // copy Gauss weights
+            //
+            for(i=ng-1; i>=0; i--)
+            {
+                wgauss[n-2-2*i] = wgauss[i];
+                wgauss[1+2*i] = wgauss[i];
+            }
+            for(i=0; i<=n/2; i++)
+            {
+                wgauss[2*i] = 0;
+            }
+            
+            //
+            // reorder
+            //
+            tsort.tagsort(ref x, n, ref p1, ref p2);
+            for(i=0; i<=n-1; i++)
+            {
+                tmp = wkronrod[i];
+                wkronrod[i] = wkronrod[p2[i]];
+                wkronrod[p2[i]] = tmp;
+                tmp = wgauss[i];
+                wgauss[i] = wgauss[p2[i]];
+                wgauss[p2[i]] = tmp;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gq.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gq.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/gq.cs	(revision 2645)
@@ -0,0 +1,734 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class gq
+    {
+        /*************************************************************************
+        Computation of nodes and weights for a Gauss quadrature formula
+
+        The algorithm generates the N-point Gauss quadrature formula  with  weight
+        function given by coefficients alpha and beta  of  a  recurrence  relation
+        which generates a system of orthogonal polynomials:
+
+        P-1(x)   =  0
+        P0(x)    =  1
+        Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)
+
+        and zeroth moment Mu0
+
+        Mu0 = integral(W(x)dx,a,b)
+
+        INPUT PARAMETERS:
+            Alpha      array[0..N-1], alpha coefficients
+            Beta       array[0..N-1], beta coefficients
+                        Zero-indexed element is not used and may be arbitrary.
+                        Beta[I]>0.
+            Mu0        zeroth moment of the weight function.
+            N          number of nodes of the quadrature formula, N>=1
+
+        OUTPUT PARAMETERS:
+            Info    -   error code:
+                        * -3    internal eigenproblem solver hasn't converged
+                        * -2    Beta[i]<=0
+                        * -1    incorrect N was passed
+                        *  1    OK
+            X       -   array[0..N-1] - array of quadrature nodes,
+                        in ascending order.
+            W       -   array[0..N-1] - array of quadrature weights.
+
+          -- ALGLIB --
+             Copyright 2005-2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgeneraterec(ref double[] alpha,
+            ref double[] beta,
+            double mu0,
+            int n,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            int i = 0;
+            double[] d = new double[0];
+            double[] e = new double[0];
+            double[,] z = new double[0,0];
+
+            if( n<1 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            
+            //
+            // Initialize
+            //
+            d = new double[n+1];
+            e = new double[n+1];
+            for(i=1; i<=n-1; i++)
+            {
+                d[i] = alpha[i-1];
+                if( (double)(beta[i])<=(double)(0) )
+                {
+                    info = -2;
+                    return;
+                }
+                e[i] = Math.Sqrt(beta[i]);
+            }
+            d[n] = alpha[n-1];
+            
+            //
+            // EVD
+            //
+            if( !tdevd.tridiagonalevd(ref d, e, n, 3, ref z) )
+            {
+                info = -3;
+                return;
+            }
+            
+            //
+            // Generate
+            //
+            x = new double[n];
+            w = new double[n];
+            for(i=1; i<=n; i++)
+            {
+                x[i-1] = d[i];
+                w[i-1] = mu0*AP.Math.Sqr(z[1,i]);
+            }
+        }
+
+
+        /*************************************************************************
+        Computation of nodes and weights for a Gauss-Lobatto quadrature formula
+
+        The algorithm generates the N-point Gauss-Lobatto quadrature formula  with
+        weight function given by coefficients alpha and beta of a recurrence which
+        generates a system of orthogonal polynomials.
+
+        P-1(x)   =  0
+        P0(x)    =  1
+        Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)
+
+        and zeroth moment Mu0
+
+        Mu0 = integral(W(x)dx,a,b)
+
+        INPUT PARAMETERS:
+            Alpha      array[0..N-2], alpha coefficients
+            Beta       array[0..N-2], beta coefficients.
+                        Zero-indexed element is not used, may be arbitrary.
+                        Beta[I]>0
+            Mu0        zeroth moment of the weighting function.
+            A          left boundary of the integration interval.
+            B          right boundary of the integration interval.
+            N          number of nodes of the quadrature formula, N>=3
+                        (including the left and right boundary nodes).
+
+        OUTPUT PARAMETERS:
+            Info    -   error code:
+                        * -3    internal eigenproblem solver hasn't converged
+                        * -2    Beta[i]<=0
+                        * -1    incorrect N was passed
+                        *  1    OK
+            X       -   array[0..N-1] - array of quadrature nodes,
+                        in ascending order.
+            W       -   array[0..N-1] - array of quadrature weights.
+
+          -- ALGLIB --
+             Copyright 2005-2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgenerategausslobattorec(double[] alpha,
+            double[] beta,
+            double mu0,
+            double a,
+            double b,
+            int n,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            int i = 0;
+            double[] d = new double[0];
+            double[] e = new double[0];
+            double[,] z = new double[0,0];
+            double pim1a = 0;
+            double pia = 0;
+            double pim1b = 0;
+            double pib = 0;
+            double t = 0;
+            double a11 = 0;
+            double a12 = 0;
+            double a21 = 0;
+            double a22 = 0;
+            double b1 = 0;
+            double b2 = 0;
+            double alph = 0;
+            double bet = 0;
+
+            alpha = (double[])alpha.Clone();
+            beta = (double[])beta.Clone();
+
+            if( n<=2 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            
+            //
+            // Initialize, D[1:N+1], E[1:N]
+            //
+            n = n-2;
+            d = new double[n+3];
+            e = new double[n+2];
+            for(i=1; i<=n+1; i++)
+            {
+                d[i] = alpha[i-1];
+            }
+            for(i=1; i<=n; i++)
+            {
+                if( (double)(beta[i])<=(double)(0) )
+                {
+                    info = -2;
+                    return;
+                }
+                e[i] = Math.Sqrt(beta[i]);
+            }
+            
+            //
+            // Caclulate Pn(a), Pn+1(a), Pn(b), Pn+1(b)
+            //
+            beta[0] = 0;
+            pim1a = 0;
+            pia = 1;
+            pim1b = 0;
+            pib = 1;
+            for(i=1; i<=n+1; i++)
+            {
+                
+                //
+                // Pi(a)
+                //
+                t = (a-alpha[i-1])*pia-beta[i-1]*pim1a;
+                pim1a = pia;
+                pia = t;
+                
+                //
+                // Pi(b)
+                //
+                t = (b-alpha[i-1])*pib-beta[i-1]*pim1b;
+                pim1b = pib;
+                pib = t;
+            }
+            
+            //
+            // Calculate alpha'(n+1), beta'(n+1)
+            //
+            a11 = pia;
+            a12 = pim1a;
+            a21 = pib;
+            a22 = pim1b;
+            b1 = a*pia;
+            b2 = b*pib;
+            if( (double)(Math.Abs(a11))>(double)(Math.Abs(a21)) )
+            {
+                a22 = a22-a12*a21/a11;
+                b2 = b2-b1*a21/a11;
+                bet = b2/a22;
+                alph = (b1-bet*a12)/a11;
+            }
+            else
+            {
+                a12 = a12-a22*a11/a21;
+                b1 = b1-b2*a11/a21;
+                bet = b1/a12;
+                alph = (b2-bet*a22)/a21;
+            }
+            if( (double)(bet)<(double)(0) )
+            {
+                info = -3;
+                return;
+            }
+            d[n+2] = alph;
+            e[n+1] = Math.Sqrt(bet);
+            
+            //
+            // EVD
+            //
+            if( !tdevd.tridiagonalevd(ref d, e, n+2, 3, ref z) )
+            {
+                info = -3;
+                return;
+            }
+            
+            //
+            // Generate
+            //
+            x = new double[n+2];
+            w = new double[n+2];
+            for(i=1; i<=n+2; i++)
+            {
+                x[i-1] = d[i];
+                w[i-1] = mu0*AP.Math.Sqr(z[1,i]);
+            }
+        }
+
+
+        /*************************************************************************
+        Computation of nodes and weights for a Gauss-Radau quadrature formula
+
+        The algorithm generates the N-point Gauss-Radau  quadrature  formula  with
+        weight function given by the coefficients alpha and  beta  of a recurrence
+        which generates a system of orthogonal polynomials.
+
+        P-1(x)   =  0
+        P0(x)    =  1
+        Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)
+
+        and zeroth moment Mu0
+
+        Mu0 = integral(W(x)dx,a,b)
+
+        INPUT PARAMETERS:
+            Alpha      array[0..N-2], alpha coefficients.
+            Beta       array[0..N-1], beta coefficients
+                        Zero-indexed element is not used.
+                        Beta[I]>0
+            Mu0        zeroth moment of the weighting function.
+            A          left boundary of the integration interval.
+            N          number of nodes of the quadrature formula, N>=2
+                        (including the left boundary node).
+
+        OUTPUT PARAMETERS:
+            Info    -   error code:
+                        * -3    internal eigenproblem solver hasn't converged
+                        * -2    Beta[i]<=0
+                        * -1    incorrect N was passed
+                        *  1    OK
+            X       -   array[0..N-1] - array of quadrature nodes,
+                        in ascending order.
+            W       -   array[0..N-1] - array of quadrature weights.
+
+
+          -- ALGLIB --
+             Copyright 2005-2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgenerategaussradaurec(double[] alpha,
+            double[] beta,
+            double mu0,
+            double a,
+            int n,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            int i = 0;
+            double[] d = new double[0];
+            double[] e = new double[0];
+            double[,] z = new double[0,0];
+            double polim1 = 0;
+            double poli = 0;
+            double t = 0;
+
+            alpha = (double[])alpha.Clone();
+            beta = (double[])beta.Clone();
+
+            if( n<2 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            
+            //
+            // Initialize, D[1:N], E[1:N]
+            //
+            n = n-1;
+            d = new double[n+1+1];
+            e = new double[n+1];
+            for(i=1; i<=n; i++)
+            {
+                d[i] = alpha[i-1];
+                if( (double)(beta[i])<=(double)(0) )
+                {
+                    info = -2;
+                    return;
+                }
+                e[i] = Math.Sqrt(beta[i]);
+            }
+            
+            //
+            // Caclulate Pn(a), Pn-1(a), and D[N+1]
+            //
+            beta[0] = 0;
+            polim1 = 0;
+            poli = 1;
+            for(i=1; i<=n; i++)
+            {
+                t = (a-alpha[i-1])*poli-beta[i-1]*polim1;
+                polim1 = poli;
+                poli = t;
+            }
+            d[n+1] = a-beta[n]*polim1/poli;
+            
+            //
+            // EVD
+            //
+            if( !tdevd.tridiagonalevd(ref d, e, n+1, 3, ref z) )
+            {
+                info = -3;
+                return;
+            }
+            
+            //
+            // Generate
+            //
+            x = new double[n+1];
+            w = new double[n+1];
+            for(i=1; i<=n+1; i++)
+            {
+                x[i-1] = d[i];
+                w[i-1] = mu0*AP.Math.Sqr(z[1,i]);
+            }
+        }
+
+
+        /*************************************************************************
+        Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N
+        nodes.
+
+        INPUT PARAMETERS:
+            N           -   number of nodes, >=1
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -4    an  error   was   detected   when  calculating
+                                    weights/nodes.  N  is  too  large   to  obtain
+                                    weights/nodes  with  high   enough   accuracy.
+                                    Try  to   use   multiple   precision  version.
+                            * -3    internal eigenproblem solver hasn't  converged
+                            * -1    incorrect N was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes,
+                            in ascending order.
+            W           -   array[0..N-1] - array of quadrature weights.
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgenerategausslegendre(int n,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            double[] alpha = new double[0];
+            double[] beta = new double[0];
+            int i = 0;
+
+            if( n<1 )
+            {
+                info = -1;
+                return;
+            }
+            alpha = new double[n];
+            beta = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                alpha[i] = 0;
+            }
+            beta[0] = 2;
+            for(i=1; i<=n-1; i++)
+            {
+                beta[i] = 1/(4-1/AP.Math.Sqr(i));
+            }
+            gqgeneraterec(ref alpha, ref beta, beta[0], n, ref info, ref x, ref w);
+            
+            //
+            // test basic properties to detect errors
+            //
+            if( info>0 )
+            {
+                if( (double)(x[0])<(double)(-1) | (double)(x[n-1])>(double)(+1) )
+                {
+                    info = -4;
+                }
+                for(i=0; i<=n-2; i++)
+                {
+                    if( (double)(x[i])>=(double)(x[i+1]) )
+                    {
+                        info = -4;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns  nodes/weights  for  Gauss-Jacobi quadrature on [-1,1] with weight
+        function W(x)=Power(1-x,Alpha)*Power(1+x,Beta).
+
+        INPUT PARAMETERS:
+            N           -   number of nodes, >=1
+            Alpha       -   power-law coefficient, Alpha>-1
+            Beta        -   power-law coefficient, Beta>-1
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -4    an  error  was   detected   when   calculating
+                                    weights/nodes. Alpha or  Beta  are  too  close
+                                    to -1 to obtain weights/nodes with high enough
+                                    accuracy, or, may be, N is too large.  Try  to
+                                    use multiple precision version.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -1    incorrect N/Alpha/Beta was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes,
+                            in ascending order.
+            W           -   array[0..N-1] - array of quadrature weights.
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgenerategaussjacobi(int n,
+            double alpha,
+            double beta,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            double[] a = new double[0];
+            double[] b = new double[0];
+            double alpha2 = 0;
+            double beta2 = 0;
+            double apb = 0;
+            double t = 0;
+            int i = 0;
+            double s = 0;
+
+            if( n<1 | (double)(alpha)<=(double)(-1) | (double)(beta)<=(double)(-1) )
+            {
+                info = -1;
+                return;
+            }
+            a = new double[n];
+            b = new double[n];
+            apb = alpha+beta;
+            a[0] = (beta-alpha)/(apb+2);
+            t = (apb+1)*Math.Log(2)+gammafunc.lngamma(alpha+1, ref s)+gammafunc.lngamma(beta+1, ref s)-gammafunc.lngamma(apb+2, ref s);
+            if( (double)(t)>(double)(Math.Log(AP.Math.MaxRealNumber)) )
+            {
+                info = -4;
+                return;
+            }
+            b[0] = Math.Exp(t);
+            if( n>1 )
+            {
+                alpha2 = AP.Math.Sqr(alpha);
+                beta2 = AP.Math.Sqr(beta);
+                a[1] = (beta2-alpha2)/((apb+2)*(apb+4));
+                b[1] = 4*(alpha+1)*(beta+1)/((apb+3)*AP.Math.Sqr(apb+2));
+                for(i=2; i<=n-1; i++)
+                {
+                    a[i] = 0.25*(beta2-alpha2)/(i*i*(1+0.5*apb/i)*(1+0.5*(apb+2)/i));
+                    b[i] = 0.25*(1+alpha/i)*(1+beta/i)*(1+apb/i)/((1+0.5*(apb+1)/i)*(1+0.5*(apb-1)/i)*AP.Math.Sqr(1+0.5*apb/i));
+                }
+            }
+            gqgeneraterec(ref a, ref b, b[0], n, ref info, ref x, ref w);
+            
+            //
+            // test basic properties to detect errors
+            //
+            if( info>0 )
+            {
+                if( (double)(x[0])<(double)(-1) | (double)(x[n-1])>(double)(+1) )
+                {
+                    info = -4;
+                }
+                for(i=0; i<=n-2; i++)
+                {
+                    if( (double)(x[i])>=(double)(x[i+1]) )
+                    {
+                        info = -4;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns  nodes/weights  for  Gauss-Laguerre  quadrature  on  [0,+inf) with
+        weight function W(x)=Power(x,Alpha)*Exp(-x)
+
+        INPUT PARAMETERS:
+            N           -   number of nodes, >=1
+            Alpha       -   power-law coefficient, Alpha>-1
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -4    an  error  was   detected   when   calculating
+                                    weights/nodes. Alpha is too  close  to  -1  to
+                                    obtain weights/nodes with high enough accuracy
+                                    or, may  be,  N  is  too  large.  Try  to  use
+                                    multiple precision version.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -1    incorrect N/Alpha was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes,
+                            in ascending order.
+            W           -   array[0..N-1] - array of quadrature weights.
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgenerategausslaguerre(int n,
+            double alpha,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            double[] a = new double[0];
+            double[] b = new double[0];
+            double t = 0;
+            int i = 0;
+            double s = 0;
+
+            if( n<1 | (double)(alpha)<=(double)(-1) )
+            {
+                info = -1;
+                return;
+            }
+            a = new double[n];
+            b = new double[n];
+            a[0] = alpha+1;
+            t = gammafunc.lngamma(alpha+1, ref s);
+            if( (double)(t)>=(double)(Math.Log(AP.Math.MaxRealNumber)) )
+            {
+                info = -4;
+                return;
+            }
+            b[0] = Math.Exp(t);
+            if( n>1 )
+            {
+                for(i=1; i<=n-1; i++)
+                {
+                    a[i] = 2*i+alpha+1;
+                    b[i] = i*(i+alpha);
+                }
+            }
+            gqgeneraterec(ref a, ref b, b[0], n, ref info, ref x, ref w);
+            
+            //
+            // test basic properties to detect errors
+            //
+            if( info>0 )
+            {
+                if( (double)(x[0])<(double)(0) )
+                {
+                    info = -4;
+                }
+                for(i=0; i<=n-2; i++)
+                {
+                    if( (double)(x[i])>=(double)(x[i+1]) )
+                    {
+                        info = -4;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns  nodes/weights  for  Gauss-Hermite  quadrature on (-inf,+inf) with
+        weight function W(x)=Exp(-x*x)
+
+        INPUT PARAMETERS:
+            N           -   number of nodes, >=1
+
+        OUTPUT PARAMETERS:
+            Info        -   error code:
+                            * -4    an  error  was   detected   when   calculating
+                                    weights/nodes.  May be, N is too large. Try to
+                                    use multiple precision version.
+                            * -3    internal eigenproblem solver hasn't converged
+                            * -1    incorrect N/Alpha was passed
+                            * +1    OK
+            X           -   array[0..N-1] - array of quadrature nodes,
+                            in ascending order.
+            W           -   array[0..N-1] - array of quadrature weights.
+
+
+          -- ALGLIB --
+             Copyright 12.05.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void gqgenerategausshermite(int n,
+            ref int info,
+            ref double[] x,
+            ref double[] w)
+        {
+            double[] a = new double[0];
+            double[] b = new double[0];
+            double t = 0;
+            int i = 0;
+            double s = 0;
+
+            if( n<1 )
+            {
+                info = -1;
+                return;
+            }
+            a = new double[n];
+            b = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                a[i] = 0;
+            }
+            b[0] = Math.Sqrt(4*Math.Atan(1));
+            if( n>1 )
+            {
+                for(i=1; i<=n-1; i++)
+                {
+                    b[i] = 0.5*i;
+                }
+            }
+            gqgeneraterec(ref a, ref b, b[0], n, ref info, ref x, ref w);
+            
+            //
+            // test basic properties to detect errors
+            //
+            if( info>0 )
+            {
+                for(i=0; i<=n-2; i++)
+                {
+                    if( (double)(x[i])>=(double)(x[i+1]) )
+                    {
+                        info = -4;
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hbisinv.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hbisinv.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hbisinv.cs	(revision 2645)
@@ -0,0 +1,500 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hbisinv
+    {
+        /*************************************************************************
+        Subroutine for finding the eigenvalues (and eigenvectors) of  a  Hermitian
+        matrix  in  a  given half-interval (A, B] by using a bisection and inverse
+        iteration
+
+        Input parameters:
+            A       -   Hermitian matrix which is given  by  its  upper  or  lower
+                        triangular  part.  Array  whose   indexes   range   within
+                        [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            ZNeeded -   flag controlling whether the eigenvectors  are  needed  or
+                        not. If ZNeeded is equal to:
+                         * 0, the eigenvectors are not returned;
+                         * 1, the eigenvectors are returned.
+            IsUpperA -  storage format of matrix A.
+            B1, B2 -    half-interval (B1, B2] to search eigenvalues in.
+
+        Output parameters:
+            M       -   number of eigenvalues found in a given half-interval, M>=0
+            W       -   array of the eigenvalues found.
+                        Array whose index ranges within [0..M-1].
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z hasnt changed;
+                         * 1, Z contains eigenvectors.
+                        Array whose indexes range within [0..N-1, 0..M-1].
+                        The eigenvectors are stored in the matrix columns.
+
+        Result:
+            True, if successful. M contains the number of eigenvalues in the given
+            half-interval (could be equal to 0), W contains the eigenvalues,
+            Z contains the eigenvectors (if needed).
+
+            False, if the bisection method subroutine  wasn't  able  to  find  the
+            eigenvalues  in  the  given  interval  or  if  the  inverse  iteration
+            subroutine  wasn't  able  to  find all the corresponding eigenvectors.
+            In that case, the eigenvalues and eigenvectors are not returned, M  is
+            equal to 0.
+
+        Note:
+            eigen vectors of Hermitian matrix are defined up to multiplication  by
+            a complex number L, such as |L|=1.
+
+          -- ALGLIB --
+             Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey.
+        *************************************************************************/
+        public static bool hmatrixevdr(AP.Complex[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            double b1,
+            double b2,
+            ref int m,
+            ref double[] w,
+            ref AP.Complex[,] z)
+        {
+            bool result = new bool();
+            AP.Complex[,] q = new AP.Complex[0,0];
+            double[,] t = new double[0,0];
+            AP.Complex[] tau = new AP.Complex[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "HermitianEigenValuesAndVectorsInInterval: incorrect ZNeeded");
+            
+            //
+            // Reduce to tridiagonal form
+            //
+            htridiagonal.hmatrixtd(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                htridiagonal.hmatrixtdunpackq(ref a, n, isupper, ref tau, ref q);
+                zneeded = 2;
+            }
+            
+            //
+            // Bisection and inverse iteration
+            //
+            result = tdbisinv.smatrixtdevdr(ref w, ref e, n, zneeded, b1, b2, ref m, ref t);
+            
+            //
+            // Eigenvectors are needed
+            // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T
+            //
+            if( result & zneeded!=0 & m!=0 )
+            {
+                work = new double[m-1+1];
+                z = new AP.Complex[n-1+1, m-1+1];
+                for(i=0; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Calculate real part
+                    //
+                    for(k=0; k<=m-1; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        v = q[i,k].x;
+                        for(i_=0; i_<=m-1;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=0; k<=m-1; k++)
+                    {
+                        z[i,k].x = work[k];
+                    }
+                    
+                    //
+                    // Calculate imaginary part
+                    //
+                    for(k=0; k<=m-1; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        v = q[i,k].y;
+                        for(i_=0; i_<=m-1;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=0; k<=m-1; k++)
+                    {
+                        z[i,k].y = work[k];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Subroutine for finding the eigenvalues and  eigenvectors  of  a  Hermitian
+        matrix with given indexes by using bisection and inverse iteration methods
+
+        Input parameters:
+            A       -   Hermitian matrix which is given  by  its  upper  or  lower
+                        triangular part.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            ZNeeded -   flag controlling whether the eigenvectors  are  needed  or
+                        not. If ZNeeded is equal to:
+                         * 0, the eigenvectors are not returned;
+                         * 1, the eigenvectors are returned.
+            IsUpperA -  storage format of matrix A.
+            I1, I2 -    index interval for searching (from I1 to I2).
+                        0 <= I1 <= I2 <= N-1.
+
+        Output parameters:
+            W       -   array of the eigenvalues found.
+                        Array whose index ranges within [0..I2-I1].
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z hasnt changed;
+                         * 1, Z contains eigenvectors.
+                        Array whose indexes range within [0..N-1, 0..I2-I1].
+                        In  that  case,  the eigenvectors are stored in the matrix
+                        columns.
+
+        Result:
+            True, if successful. W contains the eigenvalues, Z contains the
+            eigenvectors (if needed).
+
+            False, if the bisection method subroutine  wasn't  able  to  find  the
+            eigenvalues  in  the  given  interval  or  if  the  inverse  iteration
+            subroutine wasn't able to find  all  the  corresponding  eigenvectors.
+            In that case, the eigenvalues and eigenvectors are not returned.
+
+        Note:
+            eigen vectors of Hermitian matrix are defined up to multiplication  by
+            a complex number L, such as |L|=1.
+
+          -- ALGLIB --
+             Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey.
+        *************************************************************************/
+        public static bool hmatrixevdi(AP.Complex[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            int i1,
+            int i2,
+            ref double[] w,
+            ref AP.Complex[,] z)
+        {
+            bool result = new bool();
+            AP.Complex[,] q = new AP.Complex[0,0];
+            double[,] t = new double[0,0];
+            AP.Complex[] tau = new AP.Complex[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int m = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "HermitianEigenValuesAndVectorsByIndexes: incorrect ZNeeded");
+            
+            //
+            // Reduce to tridiagonal form
+            //
+            htridiagonal.hmatrixtd(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                htridiagonal.hmatrixtdunpackq(ref a, n, isupper, ref tau, ref q);
+                zneeded = 2;
+            }
+            
+            //
+            // Bisection and inverse iteration
+            //
+            result = tdbisinv.smatrixtdevdi(ref w, ref e, n, zneeded, i1, i2, ref t);
+            
+            //
+            // Eigenvectors are needed
+            // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T
+            //
+            m = i2-i1+1;
+            if( result & zneeded!=0 )
+            {
+                work = new double[m-1+1];
+                z = new AP.Complex[n-1+1, m-1+1];
+                for(i=0; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Calculate real part
+                    //
+                    for(k=0; k<=m-1; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        v = q[i,k].x;
+                        for(i_=0; i_<=m-1;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=0; k<=m-1; k++)
+                    {
+                        z[i,k].x = work[k];
+                    }
+                    
+                    //
+                    // Calculate imaginary part
+                    //
+                    for(k=0; k<=m-1; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        v = q[i,k].y;
+                        for(i_=0; i_<=m-1;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=0; k<=m-1; k++)
+                    {
+                        z[i,k].y = work[k];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool hermitianeigenvaluesandvectorsininterval(AP.Complex[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            double b1,
+            double b2,
+            ref int m,
+            ref double[] w,
+            ref AP.Complex[,] z)
+        {
+            bool result = new bool();
+            AP.Complex[,] q = new AP.Complex[0,0];
+            double[,] t = new double[0,0];
+            AP.Complex[] tau = new AP.Complex[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "HermitianEigenValuesAndVectorsInInterval: incorrect ZNeeded");
+            
+            //
+            // Reduce to tridiagonal form
+            //
+            htridiagonal.hermitiantotridiagonal(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                htridiagonal.unpackqfromhermitiantridiagonal(ref a, n, isupper, ref tau, ref q);
+                zneeded = 2;
+            }
+            
+            //
+            // Bisection and inverse iteration
+            //
+            result = tdbisinv.tridiagonaleigenvaluesandvectorsininterval(ref w, ref e, n, zneeded, b1, b2, ref m, ref t);
+            
+            //
+            // Eigenvectors are needed
+            // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T
+            //
+            if( result & zneeded!=0 & m!=0 )
+            {
+                work = new double[m+1];
+                z = new AP.Complex[n+1, m+1];
+                for(i=1; i<=n; i++)
+                {
+                    
+                    //
+                    // Calculate real part
+                    //
+                    for(k=1; k<=m; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        v = q[i,k].x;
+                        for(i_=1; i_<=m;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=1; k<=m; k++)
+                    {
+                        z[i,k].x = work[k];
+                    }
+                    
+                    //
+                    // Calculate imaginary part
+                    //
+                    for(k=1; k<=m; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        v = q[i,k].y;
+                        for(i_=1; i_<=m;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=1; k<=m; k++)
+                    {
+                        z[i,k].y = work[k];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool hermitianeigenvaluesandvectorsbyindexes(AP.Complex[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            int i1,
+            int i2,
+            ref double[] w,
+            ref AP.Complex[,] z)
+        {
+            bool result = new bool();
+            AP.Complex[,] q = new AP.Complex[0,0];
+            double[,] t = new double[0,0];
+            AP.Complex[] tau = new AP.Complex[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int m = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "HermitianEigenValuesAndVectorsByIndexes: incorrect ZNeeded");
+            
+            //
+            // Reduce to tridiagonal form
+            //
+            htridiagonal.hermitiantotridiagonal(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                htridiagonal.unpackqfromhermitiantridiagonal(ref a, n, isupper, ref tau, ref q);
+                zneeded = 2;
+            }
+            
+            //
+            // Bisection and inverse iteration
+            //
+            result = tdbisinv.tridiagonaleigenvaluesandvectorsbyindexes(ref w, ref e, n, zneeded, i1, i2, ref t);
+            
+            //
+            // Eigenvectors are needed
+            // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T
+            //
+            m = i2-i1+1;
+            if( result & zneeded!=0 )
+            {
+                work = new double[m+1];
+                z = new AP.Complex[n+1, m+1];
+                for(i=1; i<=n; i++)
+                {
+                    
+                    //
+                    // Calculate real part
+                    //
+                    for(k=1; k<=m; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        v = q[i,k].x;
+                        for(i_=1; i_<=m;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=1; k<=m; k++)
+                    {
+                        z[i,k].x = work[k];
+                    }
+                    
+                    //
+                    // Calculate imaginary part
+                    //
+                    for(k=1; k<=m; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        v = q[i,k].y;
+                        for(i_=1; i_<=m;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=1; k<=m; k++)
+                    {
+                        z[i,k].y = work[k];
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hblas.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hblas.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hblas.cs	(revision 2645)
@@ -0,0 +1,218 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hblas
+    {
+        public static void hermitianmatrixvectormultiply(ref AP.Complex[,] a,
+            bool isupper,
+            int i1,
+            int i2,
+            ref AP.Complex[] x,
+            AP.Complex alpha,
+            ref AP.Complex[] y)
+        {
+            int i = 0;
+            int ba1 = 0;
+            int ba2 = 0;
+            int by1 = 0;
+            int by2 = 0;
+            int bx1 = 0;
+            int bx2 = 0;
+            int n = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            n = i2-i1+1;
+            if( n<=0 )
+            {
+                return;
+            }
+            
+            //
+            // Let A = L + D + U, where
+            //  L is strictly lower triangular (main diagonal is zero)
+            //  D is diagonal
+            //  U is strictly upper triangular (main diagonal is zero)
+            //
+            // A*x = L*x + D*x + U*x
+            //
+            // Calculate D*x first
+            //
+            for(i=i1; i<=i2; i++)
+            {
+                y[i-i1+1] = a[i,i]*x[i-i1+1];
+            }
+            
+            //
+            // Add L*x + U*x
+            //
+            if( isupper )
+            {
+                for(i=i1; i<=i2-1; i++)
+                {
+                    
+                    //
+                    // Add L*x to the result
+                    //
+                    v = x[i-i1+1];
+                    by1 = i-i1+2;
+                    by2 = n;
+                    ba1 = i+1;
+                    ba2 = i2;
+                    i1_ = (ba1) - (by1);
+                    for(i_=by1; i_<=by2;i_++)
+                    {
+                        y[i_] = y[i_] + v*AP.Math.Conj(a[i,i_+i1_]);
+                    }
+                    
+                    //
+                    // Add U*x to the result
+                    //
+                    bx1 = i-i1+2;
+                    bx2 = n;
+                    ba1 = i+1;
+                    ba2 = i2;
+                    i1_ = (ba1)-(bx1);
+                    v = 0.0;
+                    for(i_=bx1; i_<=bx2;i_++)
+                    {
+                        v += x[i_]*a[i,i_+i1_];
+                    }
+                    y[i-i1+1] = y[i-i1+1]+v;
+                }
+            }
+            else
+            {
+                for(i=i1+1; i<=i2; i++)
+                {
+                    
+                    //
+                    // Add L*x to the result
+                    //
+                    bx1 = 1;
+                    bx2 = i-i1;
+                    ba1 = i1;
+                    ba2 = i-1;
+                    i1_ = (ba1)-(bx1);
+                    v = 0.0;
+                    for(i_=bx1; i_<=bx2;i_++)
+                    {
+                        v += x[i_]*a[i,i_+i1_];
+                    }
+                    y[i-i1+1] = y[i-i1+1]+v;
+                    
+                    //
+                    // Add U*x to the result
+                    //
+                    v = x[i-i1+1];
+                    by1 = 1;
+                    by2 = i-i1;
+                    ba1 = i1;
+                    ba2 = i-1;
+                    i1_ = (ba1) - (by1);
+                    for(i_=by1; i_<=by2;i_++)
+                    {
+                        y[i_] = y[i_] + v*AP.Math.Conj(a[i,i_+i1_]);
+                    }
+                }
+            }
+            for(i_=1; i_<=n;i_++)
+            {
+                y[i_] = alpha*y[i_];
+            }
+        }
+
+
+        public static void hermitianrank2update(ref AP.Complex[,] a,
+            bool isupper,
+            int i1,
+            int i2,
+            ref AP.Complex[] x,
+            ref AP.Complex[] y,
+            ref AP.Complex[] t,
+            AP.Complex alpha)
+        {
+            int i = 0;
+            int tp1 = 0;
+            int tp2 = 0;
+            AP.Complex v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( isupper )
+            {
+                for(i=i1; i<=i2; i++)
+                {
+                    tp1 = i+1-i1;
+                    tp2 = i2-i1+1;
+                    v = alpha*x[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = v*AP.Math.Conj(y[i_]);
+                    }
+                    v = AP.Math.Conj(alpha)*y[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = t[i_] + v*AP.Math.Conj(x[i_]);
+                    }
+                    i1_ = (tp1) - (i);
+                    for(i_=i; i_<=i2;i_++)
+                    {
+                        a[i,i_] = a[i,i_] + t[i_+i1_];
+                    }
+                }
+            }
+            else
+            {
+                for(i=i1; i<=i2; i++)
+                {
+                    tp1 = 1;
+                    tp2 = i+1-i1;
+                    v = alpha*x[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = v*AP.Math.Conj(y[i_]);
+                    }
+                    v = AP.Math.Conj(alpha)*y[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = t[i_] + v*AP.Math.Conj(x[i_]);
+                    }
+                    i1_ = (tp1) - (i1);
+                    for(i_=i1; i_<=i;i_++)
+                    {
+                        a[i,i_] = a[i,i_] + t[i_+i1_];
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hcholesky.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hcholesky.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hcholesky.cs	(revision 2645)
@@ -0,0 +1,384 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hcholesky
+    {
+        /*************************************************************************
+        Cholesky decomposition
+
+        The algorithm computes Cholesky decomposition  of  a  Hermitian  positive-
+        definite matrix.
+
+        The result of an algorithm is a representation of matrix 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. This means that the
+            factorization could not be carried out.
+
+          -- 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
+        *************************************************************************/
+        public static bool hmatrixcholesky(ref AP.Complex[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int j = 0;
+            double ajj = 0;
+            AP.Complex v = 0;
+            double r = 0;
+            AP.Complex[] t = new AP.Complex[0];
+            AP.Complex[] t2 = new AP.Complex[0];
+            AP.Complex[] t3 = new AP.Complex[0];
+            int i = 0;
+            AP.Complex[,] a1 = new AP.Complex[0,0];
+            int i_ = 0;
+
+            if( !isupper )
+            {
+                a1 = new AP.Complex[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=n; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+                result = hermitiancholeskydecomposition(ref a1, n, isupper);
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=n; j++)
+                    {
+                        a[i-1,j-1] = a1[i,j];
+                    }
+                }
+                return result;
+            }
+            t = new AP.Complex[n-1+1];
+            t2 = new AP.Complex[n-1+1];
+            t3 = new AP.Complex[n-1+1];
+            result = true;
+            if( n<0 )
+            {
+                result = false;
+                return result;
+            }
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            if( isupper )
+            {
+                
+                //
+                // Compute the Cholesky factorization A = U'*U.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    
+                    //
+                    // Compute U(J,J) and test for non-positive-definiteness.
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=j-1;i_++)
+                    {
+                        v += AP.Math.Conj(a[i_,j])*a[i_,j];
+                    }
+                    ajj = (a[j,j]-v).x;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        a[j,j] = ajj;
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N-1 of row J.
+                    //
+                    if( j<n-1 )
+                    {
+                        for(i_=0; i_<=j-1;i_++)
+                        {
+                            t2[i_] = AP.Math.Conj(a[i_,j]);
+                        }
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            t3[i_] = a[j,i_];
+                        }
+                        cblas.complexmatrixvectormultiply(ref a, 0, j-1, j+1, n-1, true, false, ref t2, 0, j-1, -1.0, ref t3, j+1, n-1, 1.0, ref t);
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[j,i_] = t3[i_];
+                        }
+                        r = 1/ajj;
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[j,i_] = r*a[j,i_];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute the Cholesky factorization A = L*L'.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    
+                    //
+                    // Compute L(J+1,J+1) and test for non-positive-definiteness.
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=j-1;i_++)
+                    {
+                        v += AP.Math.Conj(a[j,i_])*a[j,i_];
+                    }
+                    ajj = (a[j,j]-v).x;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        a[j,j] = ajj;
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of column J.
+                    //
+                    if( j<n-1 )
+                    {
+                        for(i_=0; i_<=j-1;i_++)
+                        {
+                            t2[i_] = AP.Math.Conj(a[j,i_]);
+                        }
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            t3[i_] = a[i_,j];
+                        }
+                        cblas.complexmatrixvectormultiply(ref a, j+1, n-1, 0, j-1, false, false, ref t2, 0, j-1, -1.0, ref t3, j+1, n-1, 1.0, ref t);
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[i_,j] = t3[i_];
+                        }
+                        r = 1/ajj;
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[i_,j] = r*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool hermitiancholeskydecomposition(ref AP.Complex[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int j = 0;
+            double ajj = 0;
+            AP.Complex v = 0;
+            double r = 0;
+            AP.Complex[] t = new AP.Complex[0];
+            AP.Complex[] t2 = new AP.Complex[0];
+            AP.Complex[] t3 = new AP.Complex[0];
+            int i_ = 0;
+
+            t = new AP.Complex[n+1];
+            t2 = new AP.Complex[n+1];
+            t3 = new AP.Complex[n+1];
+            result = true;
+            if( n<0 )
+            {
+                result = false;
+                return result;
+            }
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            if( isupper )
+            {
+                
+                //
+                // Compute the Cholesky factorization A = U'*U.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Compute U(J,J) and test for non-positive-definiteness.
+                    //
+                    v = 0.0;
+                    for(i_=1; i_<=j-1;i_++)
+                    {
+                        v += AP.Math.Conj(a[i_,j])*a[i_,j];
+                    }
+                    ajj = (a[j,j]-v).x;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        a[j,j] = ajj;
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of row J.
+                    //
+                    if( j<n )
+                    {
+                        for(i_=1; i_<=j-1;i_++)
+                        {
+                            a[i_,j] = AP.Math.Conj(a[i_,j]);
+                        }
+                        for(i_=1; i_<=j-1;i_++)
+                        {
+                            t2[i_] = a[i_,j];
+                        }
+                        for(i_=j+1; i_<=n;i_++)
+                        {
+                            t3[i_] = a[j,i_];
+                        }
+                        cblas.complexmatrixvectormultiply(ref a, 1, j-1, j+1, n, true, false, ref t2, 1, j-1, -1.0, ref t3, j+1, n, 1.0, ref t);
+                        for(i_=j+1; i_<=n;i_++)
+                        {
+                            a[j,i_] = t3[i_];
+                        }
+                        for(i_=1; i_<=j-1;i_++)
+                        {
+                            a[i_,j] = AP.Math.Conj(a[i_,j]);
+                        }
+                        r = 1/ajj;
+                        for(i_=j+1; i_<=n;i_++)
+                        {
+                            a[j,i_] = r*a[j,i_];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute the Cholesky factorization A = L*L'.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Compute L(J,J) and test for non-positive-definiteness.
+                    //
+                    v = 0.0;
+                    for(i_=1; i_<=j-1;i_++)
+                    {
+                        v += AP.Math.Conj(a[j,i_])*a[j,i_];
+                    }
+                    ajj = (a[j,j]-v).x;
+                    if( (double)(ajj)<=(double)(0) )
+                    {
+                        a[j,j] = ajj;
+                        result = false;
+                        return result;
+                    }
+                    ajj = Math.Sqrt(ajj);
+                    a[j,j] = ajj;
+                    
+                    //
+                    // Compute elements J+1:N of column J.
+                    //
+                    if( j<n )
+                    {
+                        for(i_=1; i_<=j-1;i_++)
+                        {
+                            a[j,i_] = AP.Math.Conj(a[j,i_]);
+                        }
+                        for(i_=1; i_<=j-1;i_++)
+                        {
+                            t2[i_] = a[j,i_];
+                        }
+                        for(i_=j+1; i_<=n;i_++)
+                        {
+                            t3[i_] = a[i_,j];
+                        }
+                        cblas.complexmatrixvectormultiply(ref a, j+1, n, 1, j-1, false, false, ref t2, 1, j-1, -1.0, ref t3, j+1, n, 1.0, ref t);
+                        for(i_=j+1; i_<=n;i_++)
+                        {
+                            a[i_,j] = t3[i_];
+                        }
+                        for(i_=1; i_<=j-1;i_++)
+                        {
+                            a[j,i_] = AP.Math.Conj(a[j,i_]);
+                        }
+                        r = 1/ajj;
+                        for(i_=j+1; i_<=n;i_++)
+                        {
+                            a[i_,j] = r*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hermite.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hermite.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hermite.cs	(revision 2645)
@@ -0,0 +1,137 @@
+/*************************************************************************
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hermite
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static double hermitecalculate(int n,
+            double x)
+        {
+            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 )
+            {
+                result = a;
+                return result;
+            }
+            if( n==1 )
+            {
+                result = b;
+                return result;
+            }
+            
+            //
+            // General case: N>=2
+            //
+            for(i=2; i<=n; i++)
+            {
+                result = 2*x*b-2*(i-1)*a;
+                a = b;
+                b = result;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Summation of Hermite polynomials using Clenshaws recurrence formula.
+
+        This routine calculates
+            c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x)
+
+        Parameters:
+            n   -   degree, n>=0
+            x   -   argument
+
+        Result:
+            the value of the Hermite polynomial at x
+        *************************************************************************/
+        public static double hermitesum(ref double[] c,
+            int n,
+            double x)
+        {
+            double result = 0;
+            double b1 = 0;
+            double b2 = 0;
+            int i = 0;
+
+            b1 = 0;
+            b2 = 0;
+            for(i=n; i>=0; i--)
+            {
+                result = 2*(x*b1-(i+1)*b2)+c[i];
+                b2 = b1;
+                b1 = result;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N
+
+        Input parameters:
+            N   -   polynomial degree, n>=0
+
+        Output parameters:
+            C   -   coefficients
+        *************************************************************************/
+        public static void hermitecoefficients(int n,
+            ref double[] c)
+        {
+            int i = 0;
+
+            c = new double[n+1];
+            for(i=0; i<=n; i++)
+            {
+                c[i] = 0;
+            }
+            c[n] = Math.Exp(n*Math.Log(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));
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hessenberg.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hessenberg.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hessenberg.cs	(revision 2645)
@@ -0,0 +1,392 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee. All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hessenberg
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static void rmatrixhessenberg(ref double[,] a,
+            int n,
+            ref double[] tau)
+        {
+            int i = 0;
+            double v = 0;
+            double[] t = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=0, "RMatrixHessenberg: incorrect N!");
+            
+            //
+            // Quick return if possible
+            //
+            if( n<=1 )
+            {
+                return;
+            }
+            tau = new double[n-2+1];
+            t = new double[n+1];
+            work = new double[n-1+1];
+            for(i=0; i<=n-2; i++)
+            {
+                
+                //
+                // Compute elementary reflector H(i) to annihilate A(i+2:ihi,i)
+                //
+                i1_ = (i+1) - (1);
+                for(i_=1; i_<=n-i-1;i_++)
+                {
+                    t[i_] = a[i_+i1_,i];
+                }
+                reflections.generatereflection(ref t, n-i-1, ref v);
+                i1_ = (1) - (i+1);
+                for(i_=i+1; i_<=n-1;i_++)
+                {
+                    a[i_,i] = t[i_+i1_];
+                }
+                tau[i] = v;
+                t[1] = 1;
+                
+                //
+                // Apply H(i) to A(1:ihi,i+1:ihi) from the right
+                //
+                reflections.applyreflectionfromtheright(ref a, v, ref t, 0, n-1, i+1, n-1, ref work);
+                
+                //
+                // Apply H(i) to A(i+1:ihi,i+1:n) from the left
+                //
+                reflections.applyreflectionfromtheleft(ref a, v, ref t, i+1, n-1, i+1, n-1, ref work);
+            }
+        }
+
+
+        /*************************************************************************
+        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].
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixhessenbergunpackq(ref double[,] a,
+            int n,
+            ref double[] tau,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new double[n-1+1, n-1+1];
+            v = new double[n-1+1];
+            work = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=0; i<=n-2; i++)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                i1_ = (i+1) - (1);
+                for(i_=1; i_<=n-i-1;i_++)
+                {
+                    v[i_] = a[i_+i1_,i];
+                }
+                v[1] = 1;
+                reflections.applyreflectionfromtheright(ref q, tau[i], ref v, 0, n-1, i+1, n-1, ref work);
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form)
+
+        Input parameters:
+            A   -   output of RMatrixHessenberg subroutine.
+            N   -   size of matrix A.
+
+        Output parameters:
+            H   -   matrix H. Array whose indexes range within [0..N-1, 0..N-1].
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixhessenbergunpackh(ref double[,] a,
+            int n,
+            ref double[,] h)
+        {
+            int i = 0;
+            int j = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            h = new double[n-1+1, n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=i-2; j++)
+                {
+                    h[i,j] = 0;
+                }
+                j = Math.Max(0, i-1);
+                for(i_=j; i_<=n-1;i_++)
+                {
+                    h[i,i_] = a[i,i_];
+                }
+            }
+        }
+
+
+        public static void toupperhessenberg(ref double[,] a,
+            int n,
+            ref double[] tau)
+        {
+            int i = 0;
+            int ip1 = 0;
+            int nmi = 0;
+            double v = 0;
+            double[] t = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=0, "ToUpperHessenberg: incorrect N!");
+            
+            //
+            // Quick return if possible
+            //
+            if( n<=1 )
+            {
+                return;
+            }
+            tau = new double[n-1+1];
+            t = new double[n+1];
+            work = new double[n+1];
+            for(i=1; i<=n-1; i++)
+            {
+                
+                //
+                // Compute elementary reflector H(i) to annihilate A(i+2:ihi,i)
+                //
+                ip1 = i+1;
+                nmi = n-i;
+                i1_ = (ip1) - (1);
+                for(i_=1; i_<=nmi;i_++)
+                {
+                    t[i_] = a[i_+i1_,i];
+                }
+                reflections.generatereflection(ref t, nmi, ref v);
+                i1_ = (1) - (ip1);
+                for(i_=ip1; i_<=n;i_++)
+                {
+                    a[i_,i] = t[i_+i1_];
+                }
+                tau[i] = v;
+                t[1] = 1;
+                
+                //
+                // Apply H(i) to A(1:ihi,i+1:ihi) from the right
+                //
+                reflections.applyreflectionfromtheright(ref a, v, ref t, 1, n, i+1, n, ref work);
+                
+                //
+                // Apply H(i) to A(i+1:ihi,i+1:n) from the left
+                //
+                reflections.applyreflectionfromtheleft(ref a, v, ref t, i+1, n, i+1, n, ref work);
+            }
+        }
+
+
+        public static void unpackqfromupperhessenberg(ref double[,] a,
+            int n,
+            ref double[] tau,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int ip1 = 0;
+            int nmi = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new double[n+1, n+1];
+            v = new double[n+1];
+            work = new double[n+1];
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=1; i<=n-1; i++)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                ip1 = i+1;
+                nmi = n-i;
+                i1_ = (ip1) - (1);
+                for(i_=1; i_<=nmi;i_++)
+                {
+                    v[i_] = a[i_+i1_,i];
+                }
+                v[1] = 1;
+                reflections.applyreflectionfromtheright(ref q, tau[i], ref v, 1, n, i+1, n, ref work);
+            }
+        }
+
+
+        public static void unpackhfromupperhessenberg(ref double[,] a,
+            int n,
+            ref double[] tau,
+            ref double[,] h)
+        {
+            int i = 0;
+            int j = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            h = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=i-2; j++)
+                {
+                    h[i,j] = 0;
+                }
+                j = Math.Max(1, i-1);
+                for(i_=j; i_<=n;i_++)
+                {
+                    h[i,i_] = a[i,i_];
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hevd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hevd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hevd.cs	(revision 2645)
@@ -0,0 +1,254 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hevd
+    {
+        /*************************************************************************
+        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 hasnt changed;
+                         * 1, Z contains the eigenvectors.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+                        The eigenvectors are stored in the matrix columns.
+
+        Result:
+            True, if the algorithm has converged.
+            False, if the algorithm hasn't converged (rare case).
+
+        Note:
+            eigen vectors of Hermitian matrix are defined up to multiplication  by
+            a complex number L, such as |L|=1.
+
+          -- ALGLIB --
+             Copyright 2005, 23 March 2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool hmatrixevd(AP.Complex[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            ref double[] d,
+            ref AP.Complex[,] z)
+        {
+            bool result = new bool();
+            AP.Complex[] tau = new AP.Complex[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            double[,] t = new double[0,0];
+            AP.Complex[,] q = new AP.Complex[0,0];
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "HermitianEVD: incorrect ZNeeded");
+            
+            //
+            // Reduce to tridiagonal form
+            //
+            htridiagonal.hmatrixtd(ref a, n, isupper, ref tau, ref d, ref e);
+            if( zneeded==1 )
+            {
+                htridiagonal.hmatrixtdunpackq(ref a, n, isupper, ref tau, ref q);
+                zneeded = 2;
+            }
+            
+            //
+            // TDEVD
+            //
+            result = tdevd.smatrixtdevd(ref d, e, n, zneeded, ref t);
+            
+            //
+            // Eigenvectors are needed
+            // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T
+            //
+            if( result & zneeded!=0 )
+            {
+                work = new double[n-1+1];
+                z = new AP.Complex[n-1+1, n-1+1];
+                for(i=0; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Calculate real part
+                    //
+                    for(k=0; k<=n-1; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        v = q[i,k].x;
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        z[i,k].x = work[k];
+                    }
+                    
+                    //
+                    // Calculate imaginary part
+                    //
+                    for(k=0; k<=n-1; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        v = q[i,k].y;
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=0; k<=n-1; k++)
+                    {
+                        z[i,k].y = work[k];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 2005, 23 March 2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool hermitianevd(AP.Complex[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            ref double[] d,
+            ref AP.Complex[,] z)
+        {
+            bool result = new bool();
+            AP.Complex[] tau = new AP.Complex[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            double[,] t = new double[0,0];
+            AP.Complex[,] q = new AP.Complex[0,0];
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int i_ = 0;
+
+            a = (AP.Complex[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "HermitianEVD: incorrect ZNeeded");
+            
+            //
+            // Reduce to tridiagonal form
+            //
+            htridiagonal.hermitiantotridiagonal(ref a, n, isupper, ref tau, ref d, ref e);
+            if( zneeded==1 )
+            {
+                htridiagonal.unpackqfromhermitiantridiagonal(ref a, n, isupper, ref tau, ref q);
+                zneeded = 2;
+            }
+            
+            //
+            // TDEVD
+            //
+            result = tdevd.tridiagonalevd(ref d, e, n, zneeded, ref t);
+            
+            //
+            // Eigenvectors are needed
+            // Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T
+            //
+            if( result & zneeded!=0 )
+            {
+                work = new double[n+1];
+                z = new AP.Complex[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    
+                    //
+                    // Calculate real part
+                    //
+                    for(k=1; k<=n; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        v = q[i,k].x;
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        z[i,k].x = work[k];
+                    }
+                    
+                    //
+                    // Calculate imaginary part
+                    //
+                    for(k=1; k<=n; k++)
+                    {
+                        work[k] = 0;
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        v = q[i,k].y;
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            work[i_] = work[i_] + v*t[k,i_];
+                        }
+                    }
+                    for(k=1; k<=n; k++)
+                    {
+                        z[i,k].y = work[k];
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hqrnd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hqrnd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hqrnd.cs	(revision 2645)
@@ -0,0 +1,284 @@
+/*************************************************************************
+Copyright (c)
+    2007, Sergey Bochkanov (ALGLIB project).
+    1988, Pierre L'Ecuyer
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hqrnd
+    {
+        /*************************************************************************
+        Portable high quality random number generator state.
+        Initialized with HQRNDRandomize() or HQRNDSeed().
+
+        Fields:
+            S1, S2      -   seed values
+            V           -   precomputed value
+            MagicV      -   'magic' value used to determine whether State structure
+                            was correctly initialized.
+        *************************************************************************/
+        public struct hqrndstate
+        {
+            public int s1;
+            public int s2;
+            public double v;
+            public int magicv;
+        };
+
+
+
+
+        public const int hqrndmax = 2147483563;
+        public const int hqrndm1 = 2147483563;
+        public const int hqrndm2 = 2147483399;
+        public const int hqrndmagic = 1634357784;
+
+
+        /*************************************************************************
+        HQRNDState  initialization  with  random  values  which come from standard
+        RNG.
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void hqrndrandomize(ref hqrndstate state)
+        {
+            hqrndseed(AP.Math.RandomInteger(hqrndm1), AP.Math.RandomInteger(hqrndm2), ref state);
+        }
+
+
+        /*************************************************************************
+        HQRNDState initialization with seed values
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void hqrndseed(int s1,
+            int s2,
+            ref hqrndstate state)
+        {
+            state.s1 = s1%(hqrndm1-1)+1;
+            state.s2 = s2%(hqrndm2-1)+1;
+            state.v = (double)(1)/(double)(hqrndmax);
+            state.magicv = hqrndmagic;
+        }
+
+
+        /*************************************************************************
+        This function generates random real number in (0,1),
+        not including interval boundaries
+
+        State structure must be initialized with HQRNDRandomize() or HQRNDSeed().
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double hqrnduniformr(ref hqrndstate state)
+        {
+            double result = 0;
+
+            result = state.v*hqrndintegerbase(ref state);
+            return result;
+        }
+
+
+        /*************************************************************************
+        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()
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static int hqrnduniformi(int n,
+            ref hqrndstate state)
+        {
+            int result = 0;
+            int mx = 0;
+
+            
+            //
+            // Correct handling of N's close to RNDBaseMax
+            // (avoiding skewed distributions for RNDBaseMax<>K*N)
+            //
+            System.Diagnostics.Debug.Assert(n>0, "HQRNDUniformI: N<=0!");
+            System.Diagnostics.Debug.Assert(n<hqrndmax-1, "HQRNDUniformI: N>=RNDBaseMax-1!");
+            mx = hqrndmax-1-(hqrndmax-1)%n;
+            do
+            {
+                result = hqrndintegerbase(ref state)-1;
+            }
+            while( result>=mx );
+            result = result%n;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Random number generator: normal numbers
+
+        This function generates one random number from normal distribution.
+        Its performance is equal to that of HQRNDNormal2()
+
+        State structure must be initialized with HQRNDRandomize() or HQRNDSeed().
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double hqrndnormal(ref hqrndstate state)
+        {
+            double result = 0;
+            double v1 = 0;
+            double v2 = 0;
+
+            hqrndnormal2(ref state, ref v1, ref v2);
+            result = v1;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Random number generator: random X and Y such that X^2+Y^2=1
+
+        State structure must be initialized with HQRNDRandomize() or HQRNDSeed().
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double hqrndunit2(ref hqrndstate state,
+            ref double x,
+            ref double y)
+        {
+            double result = 0;
+            double v = 0;
+            double mx = 0;
+            double mn = 0;
+
+            do
+            {
+                hqrndnormal2(ref state, ref x, ref y);
+            }
+            while( ! ((double)(x)!=(double)(0) | (double)(y)!=(double)(0)) );
+            mx = Math.Max(Math.Abs(x), Math.Abs(y));
+            mn = Math.Min(Math.Abs(x), Math.Abs(y));
+            v = mx*Math.Sqrt(1+AP.Math.Sqr(mn/mx));
+            x = x/v;
+            y = y/v;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Random number generator: normal numbers
+
+        This function generates two independent random numbers from normal
+        distribution. Its performance is equal to that of HQRNDNormal()
+
+        State structure must be initialized with HQRNDRandomize() or HQRNDSeed().
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void hqrndnormal2(ref hqrndstate state,
+            ref double x1,
+            ref double x2)
+        {
+            double u = 0;
+            double v = 0;
+            double s = 0;
+
+            while( true )
+            {
+                u = 2*hqrnduniformr(ref state)-1;
+                v = 2*hqrnduniformr(ref state)-1;
+                s = AP.Math.Sqr(u)+AP.Math.Sqr(v);
+                if( (double)(s)>(double)(0) & (double)(s)<(double)(1) )
+                {
+                    
+                    //
+                    // two Sqrt's instead of one to
+                    // avoid overflow when S is too small
+                    //
+                    s = Math.Sqrt(-(2*Math.Log(s)))/Math.Sqrt(s);
+                    x1 = u*s;
+                    x2 = v*s;
+                    return;
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Random number generator: exponential distribution
+
+        State structure must be initialized with HQRNDRandomize() or HQRNDSeed().
+
+          -- ALGLIB --
+             Copyright 11.08.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double hqrndexponential(double lambda,
+            ref hqrndstate state)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert((double)(lambda)>(double)(0), "HQRNDExponential: Lambda<=0!");
+            result = -(Math.Log(hqrnduniformr(ref state))/lambda);
+            return result;
+        }
+
+
+        /*************************************************************************
+
+        L'Ecuyer, Efficient and portable combined random number generators
+        *************************************************************************/
+        private static int hqrndintegerbase(ref hqrndstate state)
+        {
+            int result = 0;
+            int k = 0;
+
+            System.Diagnostics.Debug.Assert(state.magicv==hqrndmagic, "HQRNDIntegerBase: State is not correctly initialized!");
+            k = state.s1/53668;
+            state.s1 = 40014*(state.s1-k*53668)-k*12211;
+            if( state.s1<0 )
+            {
+                state.s1 = state.s1+2147483563;
+            }
+            k = state.s2/52774;
+            state.s2 = 40692*(state.s2-k*52774)-k*3791;
+            if( state.s2<0 )
+            {
+                state.s2 = state.s2+2147483399;
+            }
+            
+            //
+            // Result
+            //
+            result = state.s1-state.s2;
+            if( result<1 )
+            {
+                result = result+2147483562;
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hsschur.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hsschur.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/hsschur.cs	(revision 2645)
@@ -0,0 +1,1280 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class hsschur
+    {
+        /*************************************************************************
+        Subroutine performing  the  Schur  decomposition  of  a  matrix  in  upper
+        Hessenberg form using the QR algorithm with multiple shifts.
+
+        The  source matrix  H  is  represented as  S'*H*S = T, where H - matrix in
+        upper Hessenberg form,  S - orthogonal matrix (Schur vectors),   T - upper
+        quasi-triangular matrix (with blocks of sizes  1x1  and  2x2  on  the main
+        diagonal).
+
+        Input parameters:
+            H   -   matrix to be decomposed.
+                    Array whose indexes range within [1..N, 1..N].
+            N   -   size of H, N>=0.
+
+
+        Output parameters:
+            H      contains the matrix T.
+                    Array whose indexes range within [1..N, 1..N].
+                    All elements below the blocks on the main diagonal are equal
+                    to 0.
+            S   -   contains Schur vectors.
+                    Array whose indexes range within [1..N, 1..N].
+
+        Note 1:
+            The block structure of matrix T could be easily recognized: since  all
+            the elements  below  the blocks are zeros, the elements a[i+1,i] which
+            are equal to 0 show the block border.
+
+        Note 2:
+            the algorithm  performance  depends  on  the  value  of  the  internal
+            parameter NS of InternalSchurDecomposition  subroutine  which  defines
+            the number of shifts in the QR algorithm (analog of  the  block  width
+            in block matrix algorithms in linear algebra). If you require  maximum
+            performance  on  your  machine,  it  is  recommended  to  adjust  this
+            parameter manually.
+
+        Result:
+            True, if the algorithm has converged and the parameters H and S contain
+                the result.
+            False, if the algorithm has not converged.
+
+        Algorithm implemented on the basis of subroutine DHSEQR (LAPACK 3.0 library).
+        *************************************************************************/
+        public static bool upperhessenbergschurdecomposition(ref double[,] h,
+            int n,
+            ref double[,] s)
+        {
+            bool result = new bool();
+            double[] wi = new double[0];
+            double[] wr = new double[0];
+            int info = 0;
+
+            internalschurdecomposition(ref h, n, 1, 2, ref wr, ref wi, ref s, ref info);
+            result = info==0;
+            return result;
+        }
+
+
+        public static void internalschurdecomposition(ref double[,] h,
+            int n,
+            int tneeded,
+            int zneeded,
+            ref double[] wr,
+            ref double[] wi,
+            ref double[,] z,
+            ref int info)
+        {
+            double[] work = new double[0];
+            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;
+            double[,] s = new double[0,0];
+            double[] v = new double[0];
+            double[] vv = new double[0];
+            double[] workc1 = new double[0];
+            double[] works1 = new double[0];
+            double[] workv3 = new double[0];
+            double[] tmpwr = new double[0];
+            double[] tmpwi = new double[0];
+            bool initz = new bool();
+            bool wantt = new bool();
+            bool wantz = new bool();
+            double cnst = 0;
+            bool failflag = new bool();
+            int p1 = 0;
+            int p2 = 0;
+            double vt = 0;
+            int i_ = 0;
+            int i1_ = 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 = Math.Max(3, maxb);
+            ns = Math.Min(maxb, ns);
+            
+            //
+            // Initialize
+            //
+            cnst = 1.5;
+            work = new double[Math.Max(n, 1)+1];
+            s = new double[ns+1, ns+1];
+            v = new double[ns+1+1];
+            vv = new double[ns+1+1];
+            wr = new double[Math.Max(n, 1)+1];
+            wi = new double[Math.Max(n, 1)+1];
+            workc1 = new double[1+1];
+            works1 = new double[1+1];
+            workv3 = new double[3+1];
+            tmpwr = new double[Math.Max(n, 1)+1];
+            tmpwi = new double[Math.Max(n, 1)+1];
+            System.Diagnostics.Debug.Assert(n>=0, "InternalSchurDecomposition: incorrect N!");
+            System.Diagnostics.Debug.Assert(tneeded==0 | tneeded==1, "InternalSchurDecomposition: incorrect TNeeded!");
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1 | zneeded==2, "InternalSchurDecomposition: incorrect ZNeeded!");
+            wantt = tneeded==1;
+            initz = zneeded==2;
+            wantz = zneeded!=0;
+            info = 0;
+            
+            //
+            // Initialize Z, if necessary
+            //
+            if( initz )
+            {
+                z = new double[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=n; j++)
+                    {
+                        if( i==j )
+                        {
+                            z[i,j] = 1;
+                        }
+                        else
+                        {
+                            z[i,j] = 0;
+                        }
+                    }
+                }
+            }
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return;
+            }
+            if( n==1 )
+            {
+                wr[1] = h[1,1];
+                wi[1] = 0;
+                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,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, ref h, ref wr, ref wi, 1, n, ref z, ref work, ref workv3, ref workc1, ref works1, ref info);
+                
+                //
+                // fill entries under diagonal blocks of T with zeros
+                //
+                if( wantt )
+                {
+                    j = 1;
+                    while( j<=n )
+                    {
+                        if( (double)(wi[j])==(double)(0) )
+                        {
+                            for(i=j+1; i<=n; i++)
+                            {
+                                h[i,j] = 0;
+                            }
+                            j = j+1;
+                        }
+                        else
+                        {
+                            for(i=j+2; i<=n; i++)
+                            {
+                                h[i,j] = 0;
+                                h[i,j+1] = 0;
+                            }
+                            j = j+2;
+                        }
+                    }
+                }
+                return;
+            }
+            unfl = AP.Math.MinRealNumber;
+            ovfl = 1/unfl;
+            ulp = 2*AP.Math.MachineEpsilon;
+            smlnum = unfl*(n/ulp);
+            
+            //
+            // I1 and I2 are the indices of the first row and last column of H
+            // to which transformations must be applied. If eigenvalues only are
+            // being computed, I1 and I2 are set inside the main loop.
+            //
+            i1 = 1;
+            i2 = n;
+            
+            //
+            // ITN is the total number of multiple-shift QR iterations allowed.
+            //
+            itn = 30*n;
+            
+            //
+            // The main loop begins here. I is the loop index and decreases from
+            // IHI to ILO in steps of at most MAXB. Each iteration of the loop
+            // works with the active submatrix in rows and columns L to I.
+            // Eigenvalues I+1 to IHI have already converged. Either L = ILO or
+            // H(L,L-1) is negligible so that the matrix splits.
+            //
+            i = n;
+            while( true )
+            {
+                l = 1;
+                if( i<1 )
+                {
+                    
+                    //
+                    // fill entries under diagonal blocks of T with zeros
+                    //
+                    if( wantt )
+                    {
+                        j = 1;
+                        while( j<=n )
+                        {
+                            if( (double)(wi[j])==(double)(0) )
+                            {
+                                for(i=j+1; i<=n; i++)
+                                {
+                                    h[i,j] = 0;
+                                }
+                                j = j+1;
+                            }
+                            else
+                            {
+                                for(i=j+2; i<=n; i++)
+                                {
+                                    h[i,j] = 0;
+                                    h[i,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 = Math.Abs(h[k-1,k-1])+Math.Abs(h[k,k]);
+                        if( (double)(tst1)==(double)(0) )
+                        {
+                            tst1 = blas.upperhessenberg1norm(ref h, l, i, l, i, ref work);
+                        }
+                        if( (double)(Math.Abs(h[k,k-1]))<=(double)(Math.Max(ulp*tst1, smlnum)) )
+                        {
+                            break;
+                        }
+                    }
+                    l = k;
+                    if( l>1 )
+                    {
+                        
+                        //
+                        // H(L,L-1) is negligible.
+                        //
+                        h[l,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*(Math.Abs(h[ii,ii-1])+Math.Abs(h[ii,ii]));
+                            wi[ii] = 0;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Use eigenvalues of trailing submatrix of order NS as shifts.
+                        //
+                        blas.copymatrix(ref h, i-ns+1, i, i-ns+1, i, ref s, 1, ns, 1, ns);
+                        internalauxschur(false, false, ns, 1, ns, ref s, ref tmpwr, ref tmpwi, 1, ns, ref z, ref work, ref workv3, ref workc1, ref works1, ref ierr);
+                        for(p1=1; p1<=ns; p1++)
+                        {
+                            wr[i-ns+p1] = tmpwr[p1];
+                            wi[i-ns+p1] = tmpwi[p1];
+                        }
+                        if( ierr>0 )
+                        {
+                            
+                            //
+                            // If DLAHQR failed to compute all NS eigenvalues, use the
+                            // unconverged diagonal elements as the remaining shifts.
+                            //
+                            for(ii=1; ii<=ierr; ii++)
+                            {
+                                wr[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++)
+                    {
+                        if( (double)(wi[j])>=(double)(0) )
+                        {
+                            if( (double)(wi[j])==(double)(0) )
+                            {
+                                
+                                //
+                                // real shift
+                                //
+                                p1 = nv+1;
+                                for(i_=1; i_<=p1;i_++)
+                                {
+                                    vv[i_] = v[i_];
+                                }
+                                blas.matrixvectormultiply(ref h, l, l+nv, l, l+nv-1, false, ref vv, 1, nv, 1.0, ref v, 1, nv+1, -wr[j]);
+                                nv = nv+1;
+                            }
+                            else
+                            {
+                                if( (double)(wi[j])>(double)(0) )
+                                {
+                                    
+                                    //
+                                    // complex conjugate pair of shifts
+                                    //
+                                    p1 = nv+1;
+                                    for(i_=1; i_<=p1;i_++)
+                                    {
+                                        vv[i_] = v[i_];
+                                    }
+                                    blas.matrixvectormultiply(ref h, l, l+nv, l, l+nv-1, false, ref v, 1, nv, 1.0, ref vv, 1, nv+1, -(2*wr[j]));
+                                    itemp = blas.vectoridxabsmax(ref vv, 1, nv+1);
+                                    temp = 1/Math.Max(Math.Abs(vv[itemp]), smlnum);
+                                    p1 = nv+1;
+                                    for(i_=1; i_<=p1;i_++)
+                                    {
+                                        vv[i_] = temp*vv[i_];
+                                    }
+                                    absw = blas.pythag2(wr[j], wi[j]);
+                                    temp = temp*absw*absw;
+                                    blas.matrixvectormultiply(ref h, l, l+nv+1, l, l+nv, false, ref vv, 1, nv+1, 1.0, ref 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 = blas.vectoridxabsmax(ref v, 1, nv);
+                            temp = Math.Abs(v[itemp]);
+                            if( (double)(temp)==(double)(0) )
+                            {
+                                v[1] = 1;
+                                for(ii=2; ii<=nv; ii++)
+                                {
+                                    v[ii] = 0;
+                                }
+                            }
+                            else
+                            {
+                                temp = Math.Max(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 = Math.Min(ns+1, i-k+1);
+                        if( k>l )
+                        {
+                            p1 = k-1;
+                            p2 = k+nr-1;
+                            i1_ = (k) - (1);
+                            for(i_=1; i_<=nr;i_++)
+                            {
+                                v[i_] = h[i_+i1_,p1];
+                            }
+                        }
+                        reflections.generatereflection(ref v, nr, ref tau);
+                        if( k>l )
+                        {
+                            h[k,k-1] = v[1];
+                            for(ii=k+1; ii<=i; ii++)
+                            {
+                                h[ii,k-1] = 0;
+                            }
+                        }
+                        v[1] = 1;
+                        
+                        //
+                        // Apply G from the left to transform the rows of the matrix in
+                        // columns K to I2.
+                        //
+                        reflections.applyreflectionfromtheleft(ref h, tau, ref v, k, k+nr-1, k, i2, ref work);
+                        
+                        //
+                        // Apply G from the right to transform the columns of the
+                        // matrix in rows I1 to min(K+NR,I).
+                        //
+                        reflections.applyreflectionfromtheright(ref h, tau, ref v, i1, Math.Min(k+nr, i), k, k+nr-1, ref work);
+                        if( wantz )
+                        {
+                            
+                            //
+                            // Accumulate transformations in the matrix Z
+                            //
+                            reflections.applyreflectionfromtheright(ref z, tau, ref v, 1, n, k, k+nr-1, ref work);
+                        }
+                    }
+                }
+                
+                //
+                // Failure to converge in remaining number of iterations
+                //
+                if( failflag )
+                {
+                    info = i;
+                    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, ref h, ref wr, ref wi, 1, n, ref z, ref work, ref workv3, ref workc1, ref works1, ref info);
+                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;
+            }
+        }
+
+
+        private static void internalauxschur(bool wantt,
+            bool wantz,
+            int n,
+            int ilo,
+            int ihi,
+            ref double[,] h,
+            ref double[] wr,
+            ref double[] wi,
+            int iloz,
+            int ihiz,
+            ref double[,] z,
+            ref double[] work,
+            ref double[] workv3,
+            ref double[] workc1,
+            ref double[] works1,
+            ref int info)
+        {
+            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 = new bool();
+            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;
+
+            info = 0;
+            dat1 = 0.75;
+            dat2 = -0.4375;
+            ulp = AP.Math.MachineEpsilon;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return;
+            }
+            if( ilo==ihi )
+            {
+                wr[ilo] = h[ilo,ilo];
+                wi[ilo] = 0;
+                return;
+            }
+            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 = AP.Math.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;
+                if( i<ilo )
+                {
+                    return;
+                }
+                
+                //
+                // Perform QR iterations on rows and columns ILO to I until a
+                // submatrix of order 1 or 2 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 = Math.Abs(h[k-1,k-1])+Math.Abs(h[k,k]);
+                        if( (double)(tst1)==(double)(0) )
+                        {
+                            tst1 = blas.upperhessenberg1norm(ref h, l, i, l, i, ref work);
+                        }
+                        if( (double)(Math.Abs(h[k,k-1]))<=(double)(Math.Max(ulp*tst1, smlnum)) )
+                        {
+                            break;
+                        }
+                    }
+                    l = k;
+                    if( l>ilo )
+                    {
+                        
+                        //
+                        // H(L,L-1) is negligible
+                        //
+                        h[l,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 = Math.Abs(h[i,i-1])+Math.Abs(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;
+                        if( (double)(disc)>(double)(0) )
+                        {
+                            
+                            //
+                            // Real roots: use Wilkinson's shift twice
+                            //
+                            disc = Math.Sqrt(disc);
+                            ave = 0.5*(h33+h44);
+                            if( (double)(Math.Abs(h33)-Math.Abs(h44))>(double)(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 = Math.Abs(v1)+Math.Abs(v2)+Math.Abs(v3);
+                        v1 = v1/s;
+                        v2 = v2/s;
+                        v3 = v3/s;
+                        workv3[1] = v1;
+                        workv3[2] = v2;
+                        workv3[3] = v3;
+                        if( m==l )
+                        {
+                            break;
+                        }
+                        h00 = h[m-1,m-1];
+                        h10 = h[m,m-1];
+                        tst1 = Math.Abs(v1)*(Math.Abs(h00)+Math.Abs(h11)+Math.Abs(h22));
+                        if( (double)(Math.Abs(h10)*(Math.Abs(v2)+Math.Abs(v3)))<=(double)(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 = Math.Min(3, i-k+1);
+                        if( k>m )
+                        {
+                            for(p1=1; p1<=nr; p1++)
+                            {
+                                workv3[p1] = h[k+p1-1,k-1];
+                            }
+                        }
+                        reflections.generatereflection(ref workv3, nr, ref t1);
+                        if( k>m )
+                        {
+                            h[k,k-1] = workv3[1];
+                            h[k+1,k-1] = 0;
+                            if( k<i-1 )
+                            {
+                                h[k+2,k-1] = 0;
+                            }
+                        }
+                        else
+                        {
+                            if( m>l )
+                            {
+                                h[k,k-1] = -h[k,k-1];
+                            }
+                        }
+                        v2 = workv3[2];
+                        t2 = t1*v2;
+                        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,j] = h[k,j]-sum*t1;
+                                h[k+1,j] = h[k+1,j]-sum*t2;
+                                h[k+2,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<=Math.Min(k+3, i); j++)
+                            {
+                                sum = h[j,k]+v2*h[j,k+1]+v3*h[j,k+2];
+                                h[j,k] = h[j,k]-sum*t1;
+                                h[j,k+1] = h[j,k+1]-sum*t2;
+                                h[j,k+2] = h[j,k+2]-sum*t3;
+                            }
+                            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,k] = z[j,k]-sum*t1;
+                                    z[j,k+1] = z[j,k+1]-sum*t2;
+                                    z[j,k+2] = z[j,k+2]-sum*t3;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            if( nr==2 )
+                            {
+                                
+                                //
+                                // Apply G from the left to transform the rows of the matrix
+                                // in columns K to I2.
+                                //
+                                for(j=k; j<=i2; j++)
+                                {
+                                    sum = h[k,j]+v2*h[k+1,j];
+                                    h[k,j] = h[k,j]-sum*t1;
+                                    h[k+1,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,k] = h[j,k]-sum*t1;
+                                    h[j,k+1] = h[j,k+1]-sum*t2;
+                                }
+                                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,k] = z[j,k]-sum*t1;
+                                        z[j,k+1] = z[j,k+1]-sum*t2;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                if( failflag )
+                {
+                    
+                    //
+                    // Failure to converge in remaining number of iterations
+                    //
+                    info = i;
+                    return;
+                }
+                if( l==i )
+                {
+                    
+                    //
+                    // H(I,I-1) is negligible: one eigenvalue has converged.
+                    //
+                    wr[i] = h[i,i];
+                    wi[i] = 0;
+                }
+                else
+                {
+                    if( l==i-1 )
+                    {
+                        
+                        //
+                        // H(I-1,I-2) is negligible: a pair of eigenvalues have converged.
+                        //
+                        //        Transform the 2-by-2 submatrix to standard Schur form,
+                        //        and compute and store the eigenvalues.
+                        //
+                        him1im1 = h[i-1,i-1];
+                        him1i = h[i-1,i];
+                        hiim1 = h[i,i-1];
+                        hii = h[i,i];
+                        aux2x2schur(ref him1im1, ref him1i, ref hiim1, ref hii, ref wrim1, ref wiim1, ref wri, ref wii, ref cs, ref sn);
+                        wr[i-1] = wrim1;
+                        wi[i-1] = wiim1;
+                        wr[i] = wri;
+                        wi[i] = wii;
+                        h[i-1,i-1] = him1im1;
+                        h[i-1,i] = him1i;
+                        h[i,i-1] = hiim1;
+                        h[i,i] = hii;
+                        if( wantt )
+                        {
+                            
+                            //
+                            // Apply the transformation to the rest of H.
+                            //
+                            if( i2>i )
+                            {
+                                workc1[1] = cs;
+                                works1[1] = sn;
+                                rotations.applyrotationsfromtheleft(true, i-1, i, i+1, i2, ref workc1, ref works1, ref h, ref work);
+                            }
+                            workc1[1] = cs;
+                            works1[1] = sn;
+                            rotations.applyrotationsfromtheright(true, i1, i-2, i-1, i, ref workc1, ref works1, ref h, ref work);
+                        }
+                        if( wantz )
+                        {
+                            
+                            //
+                            // Apply the transformation to Z.
+                            //
+                            workc1[1] = cs;
+                            works1[1] = sn;
+                            rotations.applyrotationsfromtheright(true, iloz, iloz+nz-1, i-1, i, ref workc1, ref works1, ref z, ref 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;
+            }
+        }
+
+
+        private static void aux2x2schur(ref double a,
+            ref double b,
+            ref double c,
+            ref double d,
+            ref double rt1r,
+            ref double rt1i,
+            ref double rt2r,
+            ref double rt2i,
+            ref double cs,
+            ref double sn)
+        {
+            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;
+
+            multpl = 4.0;
+            eps = AP.Math.MachineEpsilon;
+            if( (double)(c)==(double)(0) )
+            {
+                cs = 1;
+                sn = 0;
+            }
+            else
+            {
+                if( (double)(b)==(double)(0) )
+                {
+                    
+                    //
+                    // Swap rows and columns
+                    //
+                    cs = 0;
+                    sn = 1;
+                    temp = d;
+                    d = a;
+                    a = temp;
+                    b = -c;
+                    c = 0;
+                }
+                else
+                {
+                    if( (double)(a-d)==(double)(0) & extschursigntoone(b)!=extschursigntoone(c) )
+                    {
+                        cs = 1;
+                        sn = 0;
+                    }
+                    else
+                    {
+                        temp = a-d;
+                        p = 0.5*temp;
+                        bcmax = Math.Max(Math.Abs(b), Math.Abs(c));
+                        bcmis = Math.Min(Math.Abs(b), Math.Abs(c))*extschursigntoone(b)*extschursigntoone(c);
+                        scl = Math.Max(Math.Abs(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( (double)(z)>=(double)(multpl*eps) )
+                        {
+                            
+                            //
+                            // Real eigenvalues. Compute A and D.
+                            //
+                            z = p+extschursign(Math.Sqrt(scl)*Math.Sqrt(z), p);
+                            a = d+z;
+                            d = d-bcmax/z*bcmis;
+                            
+                            //
+                            // Compute B and the rotation matrix
+                            //
+                            tau = blas.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 = blas.pythag2(sigma, temp);
+                            cs = Math.Sqrt(0.5*(1+Math.Abs(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;
+                            if( (double)(c)!=(double)(0) )
+                            {
+                                if( (double)(b)!=(double)(0) )
+                                {
+                                    if( extschursigntoone(b)==extschursigntoone(c) )
+                                    {
+                                        
+                                        //
+                                        // Real eigenvalues: reduce to upper triangular form
+                                        //
+                                        sab = Math.Sqrt(Math.Abs(b));
+                                        sac = Math.Sqrt(Math.Abs(c));
+                                        p = extschursign(sab*sac, c);
+                                        tau = 1/Math.Sqrt(Math.Abs(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
+                                {
+                                    b = -c;
+                                    c = 0;
+                                    temp = cs;
+                                    cs = -sn;
+                                    sn = temp;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            
+            //
+            // Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I).
+            //
+            rt1r = a;
+            rt2r = d;
+            if( (double)(c)==(double)(0) )
+            {
+                rt1i = 0;
+                rt2i = 0;
+            }
+            else
+            {
+                rt1i = Math.Sqrt(Math.Abs(b))*Math.Sqrt(Math.Abs(c));
+                rt2i = -rt1i;
+            }
+        }
+
+
+        private static double extschursign(double a,
+            double b)
+        {
+            double result = 0;
+
+            if( (double)(b)>=(double)(0) )
+            {
+                result = Math.Abs(a);
+            }
+            else
+            {
+                result = -Math.Abs(a);
+            }
+            return result;
+        }
+
+
+        private static int extschursigntoone(double b)
+        {
+            int result = 0;
+
+            if( (double)(b)>=(double)(0) )
+            {
+                result = 1;
+            }
+            else
+            {
+                result = -1;
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/htridiagonal.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/htridiagonal.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/htridiagonal.cs	(revision 2645)
@@ -0,0 +1,722 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class htridiagonal
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static void hmatrixtd(ref AP.Complex[,] a,
+            int n,
+            bool isupper,
+            ref AP.Complex[] tau,
+            ref double[] d,
+            ref double[] e)
+        {
+            int i = 0;
+            AP.Complex alpha = 0;
+            AP.Complex taui = 0;
+            AP.Complex v = 0;
+            AP.Complex[] t = new AP.Complex[0];
+            AP.Complex[] t2 = new AP.Complex[0];
+            AP.Complex[] t3 = new AP.Complex[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n<=0 )
+            {
+                return;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                System.Diagnostics.Debug.Assert((double)(a[i,i].y)==(double)(0));
+            }
+            if( n>1 )
+            {
+                tau = new AP.Complex[n-2+1];
+                e = new double[n-2+1];
+            }
+            d = new double[n-1+1];
+            t = new AP.Complex[n-1+1];
+            t2 = new AP.Complex[n-1+1];
+            t3 = new AP.Complex[n-1+1];
+            if( isupper )
+            {
+                
+                //
+                // Reduce the upper triangle of A
+                //
+                a[n-1,n-1] = a[n-1,n-1].x;
+                for(i=n-2; i>=0; i--)
+                {
+                    
+                    //
+                    // Generate elementary reflector H = I+1 - tau * v * v'
+                    //
+                    alpha = a[i,i+1];
+                    t[1] = alpha;
+                    if( i>=1 )
+                    {
+                        i1_ = (0) - (2);
+                        for(i_=2; i_<=i+1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                    }
+                    creflections.complexgeneratereflection(ref t, i+1, ref taui);
+                    if( i>=1 )
+                    {
+                        i1_ = (2) - (0);
+                        for(i_=0; i_<=i-1;i_++)
+                        {
+                            a[i_,i+1] = t[i_+i1_];
+                        }
+                    }
+                    alpha = t[1];
+                    e[i] = alpha.x;
+                    if( taui!=0 )
+                    {
+                        
+                        //
+                        // Apply H(I+1) from both sides to A
+                        //
+                        a[i,i+1] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing x in TAU
+                        //
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=i+1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                        hblas.hermitianmatrixvectormultiply(ref a, isupper, 0, i, ref t, taui, ref t2);
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            tau[i_] = t2[i_+i1_];
+                        }
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        v = 0.0;
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            v += AP.Math.Conj(tau[i_])*a[i_,i+1];
+                        }
+                        alpha = -(0.5*taui*v);
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_,i+1];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        //    A := A - v * w' - w * v'
+                        //
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=i+1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=i+1;i_++)
+                        {
+                            t3[i_] = tau[i_+i1_];
+                        }
+                        hblas.hermitianrank2update(ref a, isupper, 0, i, ref t, ref t3, ref t2, -1);
+                    }
+                    else
+                    {
+                        a[i,i] = a[i,i].x;
+                    }
+                    a[i,i+1] = e[i];
+                    d[i+1] = a[i+1,i+1].x;
+                    tau[i] = taui;
+                }
+                d[0] = a[0,0].x;
+            }
+            else
+            {
+                
+                //
+                // Reduce the lower triangle of A
+                //
+                a[0,0] = a[0,0].x;
+                for(i=0; i<=n-2; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector H = I - tau * v * v'
+                    //
+                    i1_ = (i+1) - (1);
+                    for(i_=1; i_<=n-i-1;i_++)
+                    {
+                        t[i_] = a[i_+i1_,i];
+                    }
+                    creflections.complexgeneratereflection(ref t, n-i-1, ref taui);
+                    i1_ = (1) - (i+1);
+                    for(i_=i+1; i_<=n-1;i_++)
+                    {
+                        a[i_,i] = t[i_+i1_];
+                    }
+                    e[i] = a[i+1,i].x;
+                    if( taui!=0 )
+                    {
+                        
+                        //
+                        // Apply H(i) from both sides to A(i+1:n,i+1:n)
+                        //
+                        a[i+1,i] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing y in TAU
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        hblas.hermitianmatrixvectormultiply(ref a, isupper, i+1, n-1, ref t, taui, ref t2);
+                        i1_ = (1) - (i);
+                        for(i_=i; i_<=n-2;i_++)
+                        {
+                            tau[i_] = t2[i_+i1_];
+                        }
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        i1_ = (i+1)-(i);
+                        v = 0.0;
+                        for(i_=i; i_<=n-2;i_++)
+                        {
+                            v += AP.Math.Conj(tau[i_])*a[i_+i1_,i];
+                        }
+                        alpha = -(0.5*taui*v);
+                        i1_ = (i+1) - (i);
+                        for(i_=i; i_<=n-2;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_+i1_,i];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        // A := A - v * w' - w * v'
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t2[i_] = tau[i_+i1_];
+                        }
+                        hblas.hermitianrank2update(ref a, isupper, i+1, n-1, ref t, ref t2, ref t3, -1);
+                    }
+                    else
+                    {
+                        a[i+1,i+1] = a[i+1,i+1].x;
+                    }
+                    a[i+1,i] = e[i];
+                    d[i] = a[i,i].x;
+                    tau[i] = taui;
+                }
+                d[n-1] = a[n-1,n-1].x;
+            }
+        }
+
+
+        /*************************************************************************
+        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].
+
+          -- ALGLIB --
+             Copyright 2005, 2007, 2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void hmatrixtdunpackq(ref AP.Complex[,] a,
+            int n,
+            bool isupper,
+            ref AP.Complex[] tau,
+            ref AP.Complex[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            AP.Complex[] v = new AP.Complex[0];
+            AP.Complex[] work = new AP.Complex[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new AP.Complex[n-1+1, n-1+1];
+            v = new AP.Complex[n+1];
+            work = new AP.Complex[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            if( isupper )
+            {
+                for(i=0; i<=n-2; i++)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    i1_ = (0) - (1);
+                    for(i_=1; i_<=i+1;i_++)
+                    {
+                        v[i_] = a[i_+i1_,i+1];
+                    }
+                    v[i+1] = 1;
+                    creflections.complexapplyreflectionfromtheleft(ref q, tau[i], ref v, 0, i, 0, n-1, ref work);
+                }
+            }
+            else
+            {
+                for(i=n-2; i>=0; i--)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    i1_ = (i+1) - (1);
+                    for(i_=1; i_<=n-i-1;i_++)
+                    {
+                        v[i_] = a[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    creflections.complexapplyreflectionfromtheleft(ref q, tau[i], ref v, i+1, n-1, 0, n-1, ref work);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+
+          -- 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
+        *************************************************************************/
+        public static void hermitiantotridiagonal(ref AP.Complex[,] a,
+            int n,
+            bool isupper,
+            ref AP.Complex[] tau,
+            ref double[] d,
+            ref double[] e)
+        {
+            int i = 0;
+            AP.Complex alpha = 0;
+            AP.Complex taui = 0;
+            AP.Complex v = 0;
+            AP.Complex[] t = new AP.Complex[0];
+            AP.Complex[] t2 = new AP.Complex[0];
+            AP.Complex[] t3 = new AP.Complex[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n<=0 )
+            {
+                return;
+            }
+            for(i=1; i<=n; i++)
+            {
+                System.Diagnostics.Debug.Assert((double)(a[i,i].y)==(double)(0));
+            }
+            tau = new AP.Complex[Math.Max(1, n-1)+1];
+            d = new double[n+1];
+            e = new double[Math.Max(1, n-1)+1];
+            t = new AP.Complex[n+1];
+            t2 = new AP.Complex[n+1];
+            t3 = new AP.Complex[n+1];
+            if( isupper )
+            {
+                
+                //
+                // Reduce the upper triangle of A
+                //
+                a[n,n] = a[n,n].x;
+                for(i=n-1; i>=1; i--)
+                {
+                    
+                    //
+                    // Generate elementary reflector H(i) = I - tau * v * v'
+                    // to annihilate A(1:i-1,i+1)
+                    //
+                    alpha = a[i,i+1];
+                    t[1] = alpha;
+                    if( i>=2 )
+                    {
+                        i1_ = (1) - (2);
+                        for(i_=2; i_<=i;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                    }
+                    creflections.complexgeneratereflection(ref t, i, ref taui);
+                    if( i>=2 )
+                    {
+                        i1_ = (2) - (1);
+                        for(i_=1; i_<=i-1;i_++)
+                        {
+                            a[i_,i+1] = t[i_+i1_];
+                        }
+                    }
+                    alpha = t[1];
+                    e[i] = alpha.x;
+                    if( taui!=0 )
+                    {
+                        
+                        //
+                        // Apply H(i) from both sides to A(1:i,1:i)
+                        //
+                        a[i,i+1] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing x in TAU(1:i)
+                        //
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            t[i_] = a[i_,i+1];
+                        }
+                        hblas.hermitianmatrixvectormultiply(ref a, isupper, 1, i, ref t, taui, ref tau);
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        v = 0.0;
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            v += AP.Math.Conj(tau[i_])*a[i_,i+1];
+                        }
+                        alpha = -(0.5*taui*v);
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_,i+1];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        //    A := A - v * w' - w * v'
+                        //
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            t[i_] = a[i_,i+1];
+                        }
+                        hblas.hermitianrank2update(ref a, isupper, 1, i, ref t, ref tau, ref t2, -1);
+                    }
+                    else
+                    {
+                        a[i,i] = a[i,i].x;
+                    }
+                    a[i,i+1] = e[i];
+                    d[i+1] = a[i+1,i+1].x;
+                    tau[i] = taui;
+                }
+                d[1] = a[1,1].x;
+            }
+            else
+            {
+                
+                //
+                // Reduce the lower triangle of A
+                //
+                a[1,1] = a[1,1].x;
+                for(i=1; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector H(i) = I - tau * v * v'
+                    // to annihilate A(i+2:n,i)
+                    //
+                    i1_ = (i+1) - (1);
+                    for(i_=1; i_<=n-i;i_++)
+                    {
+                        t[i_] = a[i_+i1_,i];
+                    }
+                    creflections.complexgeneratereflection(ref t, n-i, ref taui);
+                    i1_ = (1) - (i+1);
+                    for(i_=i+1; i_<=n;i_++)
+                    {
+                        a[i_,i] = t[i_+i1_];
+                    }
+                    e[i] = a[i+1,i].x;
+                    if( taui!=0 )
+                    {
+                        
+                        //
+                        // Apply H(i) from both sides to A(i+1:n,i+1:n)
+                        //
+                        a[i+1,i] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing y in TAU(i:n-1)
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        hblas.hermitianmatrixvectormultiply(ref a, isupper, i+1, n, ref t, taui, ref t2);
+                        i1_ = (1) - (i);
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            tau[i_] = t2[i_+i1_];
+                        }
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        i1_ = (i+1)-(i);
+                        v = 0.0;
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            v += AP.Math.Conj(tau[i_])*a[i_+i1_,i];
+                        }
+                        alpha = -(0.5*taui*v);
+                        i1_ = (i+1) - (i);
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_+i1_,i];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        // A := A - v * w' - w * v'
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=n-i;i_++)
+                        {
+                            t2[i_] = tau[i_+i1_];
+                        }
+                        hblas.hermitianrank2update(ref a, isupper, i+1, n, ref t, ref t2, ref t3, -1);
+                    }
+                    else
+                    {
+                        a[i+1,i+1] = a[i+1,i+1].x;
+                    }
+                    a[i+1,i] = e[i];
+                    d[i] = a[i,i].x;
+                    tau[i] = taui;
+                }
+                d[n] = a[n,n].x;
+            }
+        }
+
+
+        /*************************************************************************
+
+          -- ALGLIB --
+             Copyright 2005, 2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void unpackqfromhermitiantridiagonal(ref AP.Complex[,] a,
+            int n,
+            bool isupper,
+            ref AP.Complex[] tau,
+            ref AP.Complex[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            AP.Complex[] v = new AP.Complex[0];
+            AP.Complex[] work = new AP.Complex[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new AP.Complex[n+1, n+1];
+            v = new AP.Complex[n+1];
+            work = new AP.Complex[n+1];
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            if( isupper )
+            {
+                for(i=1; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    for(i_=1; i_<=i;i_++)
+                    {
+                        v[i_] = a[i_,i+1];
+                    }
+                    v[i] = 1;
+                    creflections.complexapplyreflectionfromtheleft(ref q, tau[i], ref v, 1, i, 1, n, ref work);
+                }
+            }
+            else
+            {
+                for(i=n-1; i>=1; i--)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    i1_ = (i+1) - (1);
+                    for(i_=1; i_<=n-i;i_++)
+                    {
+                        v[i_] = a[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    creflections.complexapplyreflectionfromtheleft(ref q, tau[i], ref v, i+1, n, 1, n, ref work);
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ibetaf.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ibetaf.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ibetaf.cs	(revision 2645)
@@ -0,0 +1,945 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ibetaf
+    {
+        /*************************************************************************
+        Incomplete beta integral
+
+        Returns incomplete beta integral of the arguments, evaluated
+        from zero to x.  The function is defined as
+
+                         x
+            -            -
+           | (a+b)      | |  a-1     b-1
+         -----------    |   t   (1-t)   dt.
+          -     -     | |
+         | (a) | (b)   -
+                        0
+
+        The domain of definition is 0 <= x <= 1.  In this
+        implementation a and b are restricted to positive values.
+        The integral from x to 1 may be obtained by the symmetry
+        relation
+
+           1 - incbet( a, b, x )  =  incbet( b, a, 1-x ).
+
+        The integral is evaluated by a continued fraction expansion
+        or, when b*x is small, by a power series.
+
+        ACCURACY:
+
+        Tested at uniformly distributed random points (a,b,x) with a and b
+        in "domain" and x between 0 and 1.
+                                               Relative error
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,5         10000       6.9e-15     4.5e-16
+           IEEE      0,85       250000       2.2e-13     1.7e-14
+           IEEE      0,1000      30000       5.3e-12     6.3e-13
+           IEEE      0,10000    250000       9.3e-11     7.1e-12
+           IEEE      0,100000    10000       8.7e-10     4.8e-11
+        Outputs smaller than the IEEE gradual underflow threshold
+        were excluded from these statistics.
+
+        Cephes Math Library, Release 2.8:  June, 2000
+        Copyright 1984, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double incompletebeta(double a,
+            double b,
+            double x)
+        {
+            double result = 0;
+            double t = 0;
+            double xc = 0;
+            double w = 0;
+            double y = 0;
+            int flag = 0;
+            double sg = 0;
+            double big = 0;
+            double biginv = 0;
+            double maxgam = 0;
+            double minlog = 0;
+            double maxlog = 0;
+
+            big = 4.503599627370496e15;
+            biginv = 2.22044604925031308085e-16;
+            maxgam = 171.624376956302725;
+            minlog = Math.Log(AP.Math.MinRealNumber);
+            maxlog = Math.Log(AP.Math.MaxRealNumber);
+            System.Diagnostics.Debug.Assert((double)(a)>(double)(0) & (double)(b)>(double)(0), "Domain error in IncompleteBeta");
+            System.Diagnostics.Debug.Assert((double)(x)>=(double)(0) & (double)(x)<=(double)(1), "Domain error in IncompleteBeta");
+            if( (double)(x)==(double)(0) )
+            {
+                result = 0;
+                return result;
+            }
+            if( (double)(x)==(double)(1) )
+            {
+                result = 1;
+                return result;
+            }
+            flag = 0;
+            if( (double)(b*x)<=(double)(1.0) & (double)(x)<=(double)(0.95) )
+            {
+                result = incompletebetaps(a, b, x, maxgam);
+                return result;
+            }
+            w = 1.0-x;
+            if( (double)(x)>(double)(a/(a+b)) )
+            {
+                flag = 1;
+                t = a;
+                a = b;
+                b = t;
+                xc = x;
+                x = w;
+            }
+            else
+            {
+                xc = w;
+            }
+            if( flag==1 & (double)(b*x)<=(double)(1.0) & (double)(x)<=(double)(0.95) )
+            {
+                t = incompletebetaps(a, b, x, maxgam);
+                if( (double)(t)<=(double)(AP.Math.MachineEpsilon) )
+                {
+                    result = 1.0-AP.Math.MachineEpsilon;
+                }
+                else
+                {
+                    result = 1.0-t;
+                }
+                return result;
+            }
+            y = x*(a+b-2.0)-(a-1.0);
+            if( (double)(y)<(double)(0.0) )
+            {
+                w = incompletebetafe(a, b, x, big, biginv);
+            }
+            else
+            {
+                w = incompletebetafe2(a, b, x, big, biginv)/xc;
+            }
+            y = a*Math.Log(x);
+            t = b*Math.Log(xc);
+            if( (double)(a+b)<(double)(maxgam) & (double)(Math.Abs(y))<(double)(maxlog) & (double)(Math.Abs(t))<(double)(maxlog) )
+            {
+                t = Math.Pow(xc, b);
+                t = t*Math.Pow(x, a);
+                t = t/a;
+                t = t*w;
+                t = t*(gammafunc.gamma(a+b)/(gammafunc.gamma(a)*gammafunc.gamma(b)));
+                if( flag==1 )
+                {
+                    if( (double)(t)<=(double)(AP.Math.MachineEpsilon) )
+                    {
+                        result = 1.0-AP.Math.MachineEpsilon;
+                    }
+                    else
+                    {
+                        result = 1.0-t;
+                    }
+                }
+                else
+                {
+                    result = t;
+                }
+                return result;
+            }
+            y = y+t+gammafunc.lngamma(a+b, ref sg)-gammafunc.lngamma(a, ref sg)-gammafunc.lngamma(b, ref sg);
+            y = y+Math.Log(w/a);
+            if( (double)(y)<(double)(minlog) )
+            {
+                t = 0.0;
+            }
+            else
+            {
+                t = Math.Exp(y);
+            }
+            if( flag==1 )
+            {
+                if( (double)(t)<=(double)(AP.Math.MachineEpsilon) )
+                {
+                    t = 1.0-AP.Math.MachineEpsilon;
+                }
+                else
+                {
+                    t = 1.0-t;
+                }
+            }
+            result = t;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse of imcomplete beta integral
+
+        Given y, the function finds x such that
+
+         incbet( a, b, x ) = y .
+
+        The routine performs interval halving or Newton iterations to find the
+        root of incbet(a,b,x) - y = 0.
+
+
+        ACCURACY:
+
+                             Relative error:
+                       x     a,b
+        arithmetic   domain  domain  # trials    peak       rms
+           IEEE      0,1    .5,10000   50000    5.8e-12   1.3e-13
+           IEEE      0,1   .25,100    100000    1.8e-13   3.9e-15
+           IEEE      0,1     0,5       50000    1.1e-12   5.5e-15
+        With a and b constrained to half-integer or integer values:
+           IEEE      0,1    .5,10000   50000    5.8e-12   1.1e-13
+           IEEE      0,1    .5,100    100000    1.7e-14   7.9e-16
+        With a = .5, b constrained to half-integer or integer values:
+           IEEE      0,1    .5,10000   10000    8.3e-11   1.0e-11
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1996, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invincompletebeta(double a,
+            double b,
+            double y)
+        {
+            double result = 0;
+            double aaa = 0;
+            double bbb = 0;
+            double y0 = 0;
+            double d = 0;
+            double yyy = 0;
+            double x = 0;
+            double x0 = 0;
+            double x1 = 0;
+            double lgm = 0;
+            double yp = 0;
+            double di = 0;
+            double dithresh = 0;
+            double yl = 0;
+            double yh = 0;
+            double xt = 0;
+            int i = 0;
+            int rflg = 0;
+            int dir = 0;
+            int nflg = 0;
+            double s = 0;
+            int mainlooppos = 0;
+            int ihalve = 0;
+            int ihalvecycle = 0;
+            int newt = 0;
+            int newtcycle = 0;
+            int breaknewtcycle = 0;
+            int breakihalvecycle = 0;
+
+            i = 0;
+            System.Diagnostics.Debug.Assert((double)(y)>=(double)(0) & (double)(y)<=(double)(1), "Domain error in InvIncompleteBeta");
+            if( (double)(y)==(double)(0) )
+            {
+                result = 0;
+                return result;
+            }
+            if( (double)(y)==(double)(1.0) )
+            {
+                result = 1;
+                return result;
+            }
+            x0 = 0.0;
+            yl = 0.0;
+            x1 = 1.0;
+            yh = 1.0;
+            nflg = 0;
+            mainlooppos = 0;
+            ihalve = 1;
+            ihalvecycle = 2;
+            newt = 3;
+            newtcycle = 4;
+            breaknewtcycle = 5;
+            breakihalvecycle = 6;
+            while( true )
+            {
+                
+                //
+                // start
+                //
+                if( mainlooppos==0 )
+                {
+                    if( (double)(a)<=(double)(1.0) | (double)(b)<=(double)(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;
+                    }
+                    yp = -normaldistr.invnormaldistribution(y);
+                    if( (double)(y)>(double)(0.5) )
+                    {
+                        rflg = 1;
+                        aaa = b;
+                        bbb = a;
+                        y0 = 1.0-y;
+                        yp = -yp;
+                    }
+                    else
+                    {
+                        rflg = 0;
+                        aaa = a;
+                        bbb = b;
+                        y0 = y;
+                    }
+                    lgm = (yp*yp-3.0)/6.0;
+                    x = 2.0/(1.0/(2.0*aaa-1.0)+1.0/(2.0*bbb-1.0));
+                    d = yp*Math.Sqrt(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;
+                    if( (double)(d)<(double)(Math.Log(AP.Math.MinRealNumber)) )
+                    {
+                        x = 0;
+                        break;
+                    }
+                    x = aaa/(aaa+bbb*Math.Exp(d));
+                    yyy = incompletebeta(aaa, bbb, x);
+                    yp = (yyy-y0)/y0;
+                    if( (double)(Math.Abs(yp))<(double)(0.2) )
+                    {
+                        mainlooppos = newt;
+                        continue;
+                    }
+                    mainlooppos = ihalve;
+                    continue;
+                }
+                
+                //
+                // ihalve
+                //
+                if( mainlooppos==ihalve )
+                {
+                    dir = 0;
+                    di = 0.5;
+                    i = 0;
+                    mainlooppos = ihalvecycle;
+                    continue;
+                }
+                
+                //
+                // ihalvecycle
+                //
+                if( mainlooppos==ihalvecycle )
+                {
+                    if( i<=99 )
+                    {
+                        if( i!=0 )
+                        {
+                            x = x0+di*(x1-x0);
+                            if( (double)(x)==(double)(1.0) )
+                            {
+                                x = 1.0-AP.Math.MachineEpsilon;
+                            }
+                            if( (double)(x)==(double)(0.0) )
+                            {
+                                di = 0.5;
+                                x = x0+di*(x1-x0);
+                                if( (double)(x)==(double)(0.0) )
+                                {
+                                    break;
+                                }
+                            }
+                            yyy = incompletebeta(aaa, bbb, x);
+                            yp = (x1-x0)/(x1+x0);
+                            if( (double)(Math.Abs(yp))<(double)(dithresh) )
+                            {
+                                mainlooppos = newt;
+                                continue;
+                            }
+                            yp = (yyy-y0)/y0;
+                            if( (double)(Math.Abs(yp))<(double)(dithresh) )
+                            {
+                                mainlooppos = newt;
+                                continue;
+                            }
+                        }
+                        if( (double)(yyy)<(double)(y0) )
+                        {
+                            x0 = x;
+                            yl = yyy;
+                            if( dir<0 )
+                            {
+                                dir = 0;
+                                di = 0.5;
+                            }
+                            else
+                            {
+                                if( dir>3 )
+                                {
+                                    di = 1.0-(1.0-di)*(1.0-di);
+                                }
+                                else
+                                {
+                                    if( dir>1 )
+                                    {
+                                        di = 0.5*di+0.5;
+                                    }
+                                    else
+                                    {
+                                        di = (y0-yyy)/(yh-yl);
+                                    }
+                                }
+                            }
+                            dir = dir+1;
+                            if( (double)(x0)>(double)(0.75) )
+                            {
+                                if( rflg==1 )
+                                {
+                                    rflg = 0;
+                                    aaa = a;
+                                    bbb = b;
+                                    y0 = y;
+                                }
+                                else
+                                {
+                                    rflg = 1;
+                                    aaa = b;
+                                    bbb = a;
+                                    y0 = 1.0-y;
+                                }
+                                x = 1.0-x;
+                                yyy = incompletebeta(aaa, bbb, x);
+                                x0 = 0.0;
+                                yl = 0.0;
+                                x1 = 1.0;
+                                yh = 1.0;
+                                mainlooppos = ihalve;
+                                continue;
+                            }
+                        }
+                        else
+                        {
+                            x1 = x;
+                            if( rflg==1 & (double)(x1)<(double)(AP.Math.MachineEpsilon) )
+                            {
+                                x = 0.0;
+                                break;
+                            }
+                            yh = yyy;
+                            if( dir>0 )
+                            {
+                                dir = 0;
+                                di = 0.5;
+                            }
+                            else
+                            {
+                                if( dir<-3 )
+                                {
+                                    di = di*di;
+                                }
+                                else
+                                {
+                                    if( dir<-1 )
+                                    {
+                                        di = 0.5*di;
+                                    }
+                                    else
+                                    {
+                                        di = (yyy-y0)/(yh-yl);
+                                    }
+                                }
+                            }
+                            dir = dir-1;
+                        }
+                        i = i+1;
+                        mainlooppos = ihalvecycle;
+                        continue;
+                    }
+                    else
+                    {
+                        mainlooppos = breakihalvecycle;
+                        continue;
+                    }
+                }
+                
+                //
+                // breakihalvecycle
+                //
+                if( mainlooppos==breakihalvecycle )
+                {
+                    if( (double)(x0)>=(double)(1.0) )
+                    {
+                        x = 1.0-AP.Math.MachineEpsilon;
+                        break;
+                    }
+                    if( (double)(x)<=(double)(0.0) )
+                    {
+                        x = 0.0;
+                        break;
+                    }
+                    mainlooppos = newt;
+                    continue;
+                }
+                
+                //
+                // newt
+                //
+                if( mainlooppos==newt )
+                {
+                    if( nflg!=0 )
+                    {
+                        break;
+                    }
+                    nflg = 1;
+                    lgm = gammafunc.lngamma(aaa+bbb, ref s)-gammafunc.lngamma(aaa, ref s)-gammafunc.lngamma(bbb, ref s);
+                    i = 0;
+                    mainlooppos = newtcycle;
+                    continue;
+                }
+                
+                //
+                // newtcycle
+                //
+                if( mainlooppos==newtcycle )
+                {
+                    if( i<=7 )
+                    {
+                        if( i!=0 )
+                        {
+                            yyy = incompletebeta(aaa, bbb, x);
+                        }
+                        if( (double)(yyy)<(double)(yl) )
+                        {
+                            x = x0;
+                            yyy = yl;
+                        }
+                        else
+                        {
+                            if( (double)(yyy)>(double)(yh) )
+                            {
+                                x = x1;
+                                yyy = yh;
+                            }
+                            else
+                            {
+                                if( (double)(yyy)<(double)(y0) )
+                                {
+                                    x0 = x;
+                                    yl = yyy;
+                                }
+                                else
+                                {
+                                    x1 = x;
+                                    yh = yyy;
+                                }
+                            }
+                        }
+                        if( (double)(x)==(double)(1.0) | (double)(x)==(double)(0.0) )
+                        {
+                            mainlooppos = breaknewtcycle;
+                            continue;
+                        }
+                        d = (aaa-1.0)*Math.Log(x)+(bbb-1.0)*Math.Log(1.0-x)+lgm;
+                        if( (double)(d)<(double)(Math.Log(AP.Math.MinRealNumber)) )
+                        {
+                            break;
+                        }
+                        if( (double)(d)>(double)(Math.Log(AP.Math.MaxRealNumber)) )
+                        {
+                            mainlooppos = breaknewtcycle;
+                            continue;
+                        }
+                        d = Math.Exp(d);
+                        d = (yyy-y0)/d;
+                        xt = x-d;
+                        if( (double)(xt)<=(double)(x0) )
+                        {
+                            yyy = (x-x0)/(x1-x0);
+                            xt = x0+0.5*yyy*(x-x0);
+                            if( (double)(xt)<=(double)(0.0) )
+                            {
+                                mainlooppos = breaknewtcycle;
+                                continue;
+                            }
+                        }
+                        if( (double)(xt)>=(double)(x1) )
+                        {
+                            yyy = (x1-x)/(x1-x0);
+                            xt = x1-0.5*yyy*(x1-x);
+                            if( (double)(xt)>=(double)(1.0) )
+                            {
+                                mainlooppos = breaknewtcycle;
+                                continue;
+                            }
+                        }
+                        x = xt;
+                        if( (double)(Math.Abs(d/x))<(double)(128.0*AP.Math.MachineEpsilon) )
+                        {
+                            break;
+                        }
+                        i = i+1;
+                        mainlooppos = newtcycle;
+                        continue;
+                    }
+                    else
+                    {
+                        mainlooppos = breaknewtcycle;
+                        continue;
+                    }
+                }
+                
+                //
+                // breaknewtcycle
+                //
+                if( mainlooppos==breaknewtcycle )
+                {
+                    dithresh = 256.0*AP.Math.MachineEpsilon;
+                    mainlooppos = ihalve;
+                    continue;
+                }
+            }
+            
+            //
+            // done
+            //
+            if( rflg!=0 )
+            {
+                if( (double)(x)<=(double)(AP.Math.MachineEpsilon) )
+                {
+                    x = 1.0-AP.Math.MachineEpsilon;
+                }
+                else
+                {
+                    x = 1.0-x;
+                }
+            }
+            result = x;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Continued fraction expansion #1 for incomplete beta integral
+
+        Cephes Math Library, Release 2.8:  June, 2000
+        Copyright 1984, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static double incompletebetafe(double a,
+            double b,
+            double x,
+            double big,
+            double biginv)
+        {
+            double result = 0;
+            double xk = 0;
+            double pk = 0;
+            double pkm1 = 0;
+            double pkm2 = 0;
+            double qk = 0;
+            double qkm1 = 0;
+            double qkm2 = 0;
+            double k1 = 0;
+            double k2 = 0;
+            double k3 = 0;
+            double k4 = 0;
+            double k5 = 0;
+            double k6 = 0;
+            double k7 = 0;
+            double k8 = 0;
+            double r = 0;
+            double t = 0;
+            double ans = 0;
+            double thresh = 0;
+            int n = 0;
+
+            k1 = a;
+            k2 = a+b;
+            k3 = a;
+            k4 = a+1.0;
+            k5 = 1.0;
+            k6 = b-1.0;
+            k7 = k4;
+            k8 = a+2.0;
+            pkm2 = 0.0;
+            qkm2 = 1.0;
+            pkm1 = 1.0;
+            qkm1 = 1.0;
+            ans = 1.0;
+            r = 1.0;
+            n = 0;
+            thresh = 3.0*AP.Math.MachineEpsilon;
+            do
+            {
+                xk = -(x*k1*k2/(k3*k4));
+                pk = pkm1+pkm2*xk;
+                qk = qkm1+qkm2*xk;
+                pkm2 = pkm1;
+                pkm1 = pk;
+                qkm2 = qkm1;
+                qkm1 = qk;
+                xk = x*k5*k6/(k7*k8);
+                pk = pkm1+pkm2*xk;
+                qk = qkm1+qkm2*xk;
+                pkm2 = pkm1;
+                pkm1 = pk;
+                qkm2 = qkm1;
+                qkm1 = qk;
+                if( (double)(qk)!=(double)(0) )
+                {
+                    r = pk/qk;
+                }
+                if( (double)(r)!=(double)(0) )
+                {
+                    t = Math.Abs((ans-r)/r);
+                    ans = r;
+                }
+                else
+                {
+                    t = 1.0;
+                }
+                if( (double)(t)<(double)(thresh) )
+                {
+                    break;
+                }
+                k1 = k1+1.0;
+                k2 = k2+1.0;
+                k3 = k3+2.0;
+                k4 = k4+2.0;
+                k5 = k5+1.0;
+                k6 = k6-1.0;
+                k7 = k7+2.0;
+                k8 = k8+2.0;
+                if( (double)(Math.Abs(qk)+Math.Abs(pk))>(double)(big) )
+                {
+                    pkm2 = pkm2*biginv;
+                    pkm1 = pkm1*biginv;
+                    qkm2 = qkm2*biginv;
+                    qkm1 = qkm1*biginv;
+                }
+                if( (double)(Math.Abs(qk))<(double)(biginv) | (double)(Math.Abs(pk))<(double)(biginv) )
+                {
+                    pkm2 = pkm2*big;
+                    pkm1 = pkm1*big;
+                    qkm2 = qkm2*big;
+                    qkm1 = qkm1*big;
+                }
+                n = n+1;
+            }
+            while( n!=300 );
+            result = ans;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Continued fraction expansion #2
+        for incomplete beta integral
+
+        Cephes Math Library, Release 2.8:  June, 2000
+        Copyright 1984, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static double incompletebetafe2(double a,
+            double b,
+            double x,
+            double big,
+            double biginv)
+        {
+            double result = 0;
+            double xk = 0;
+            double pk = 0;
+            double pkm1 = 0;
+            double pkm2 = 0;
+            double qk = 0;
+            double qkm1 = 0;
+            double qkm2 = 0;
+            double k1 = 0;
+            double k2 = 0;
+            double k3 = 0;
+            double k4 = 0;
+            double k5 = 0;
+            double k6 = 0;
+            double k7 = 0;
+            double k8 = 0;
+            double r = 0;
+            double t = 0;
+            double ans = 0;
+            double z = 0;
+            double thresh = 0;
+            int n = 0;
+
+            k1 = a;
+            k2 = b-1.0;
+            k3 = a;
+            k4 = a+1.0;
+            k5 = 1.0;
+            k6 = a+b;
+            k7 = a+1.0;
+            k8 = a+2.0;
+            pkm2 = 0.0;
+            qkm2 = 1.0;
+            pkm1 = 1.0;
+            qkm1 = 1.0;
+            z = x/(1.0-x);
+            ans = 1.0;
+            r = 1.0;
+            n = 0;
+            thresh = 3.0*AP.Math.MachineEpsilon;
+            do
+            {
+                xk = -(z*k1*k2/(k3*k4));
+                pk = pkm1+pkm2*xk;
+                qk = qkm1+qkm2*xk;
+                pkm2 = pkm1;
+                pkm1 = pk;
+                qkm2 = qkm1;
+                qkm1 = qk;
+                xk = z*k5*k6/(k7*k8);
+                pk = pkm1+pkm2*xk;
+                qk = qkm1+qkm2*xk;
+                pkm2 = pkm1;
+                pkm1 = pk;
+                qkm2 = qkm1;
+                qkm1 = qk;
+                if( (double)(qk)!=(double)(0) )
+                {
+                    r = pk/qk;
+                }
+                if( (double)(r)!=(double)(0) )
+                {
+                    t = Math.Abs((ans-r)/r);
+                    ans = r;
+                }
+                else
+                {
+                    t = 1.0;
+                }
+                if( (double)(t)<(double)(thresh) )
+                {
+                    break;
+                }
+                k1 = k1+1.0;
+                k2 = k2-1.0;
+                k3 = k3+2.0;
+                k4 = k4+2.0;
+                k5 = k5+1.0;
+                k6 = k6+1.0;
+                k7 = k7+2.0;
+                k8 = k8+2.0;
+                if( (double)(Math.Abs(qk)+Math.Abs(pk))>(double)(big) )
+                {
+                    pkm2 = pkm2*biginv;
+                    pkm1 = pkm1*biginv;
+                    qkm2 = qkm2*biginv;
+                    qkm1 = qkm1*biginv;
+                }
+                if( (double)(Math.Abs(qk))<(double)(biginv) | (double)(Math.Abs(pk))<(double)(biginv) )
+                {
+                    pkm2 = pkm2*big;
+                    pkm1 = pkm1*big;
+                    qkm2 = qkm2*big;
+                    qkm1 = qkm1*big;
+                }
+                n = n+1;
+            }
+            while( n!=300 );
+            result = ans;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Power series for incomplete beta integral.
+        Use when b*x is small and x not too close to 1.
+
+        Cephes Math Library, Release 2.8:  June, 2000
+        Copyright 1984, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        private static double incompletebetaps(double a,
+            double b,
+            double x,
+            double maxgam)
+        {
+            double result = 0;
+            double s = 0;
+            double t = 0;
+            double u = 0;
+            double v = 0;
+            double n = 0;
+            double t1 = 0;
+            double z = 0;
+            double ai = 0;
+            double sg = 0;
+
+            ai = 1.0/a;
+            u = (1.0-b)*x;
+            v = u/(a+1.0);
+            t1 = v;
+            t = u;
+            n = 2.0;
+            s = 0.0;
+            z = AP.Math.MachineEpsilon*ai;
+            while( (double)(Math.Abs(v))>(double)(z) )
+            {
+                u = (n-b)*x/n;
+                t = t*u;
+                v = t/(a+n);
+                s = s+v;
+                n = n+1.0;
+            }
+            s = s+t1;
+            s = s+ai;
+            u = a*Math.Log(x);
+            if( (double)(a+b)<(double)(maxgam) & (double)(Math.Abs(u))<(double)(Math.Log(AP.Math.MaxRealNumber)) )
+            {
+                t = gammafunc.gamma(a+b)/(gammafunc.gamma(a)*gammafunc.gamma(b));
+                s = s*t*Math.Pow(x, a);
+            }
+            else
+            {
+                t = gammafunc.lngamma(a+b, ref sg)-gammafunc.lngamma(a, ref sg)-gammafunc.lngamma(b, ref sg)+u+Math.Log(s);
+                if( (double)(t)<(double)(Math.Log(AP.Math.MinRealNumber)) )
+                {
+                    s = 0.0;
+                }
+                else
+                {
+                    s = Math.Exp(t);
+                }
+            }
+            result = s;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/igammaf.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/igammaf.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/igammaf.cs	(revision 2645)
@@ -0,0 +1,423 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class igammaf
+    {
+        /*************************************************************************
+        Incomplete gamma integral
+
+        The function is defined by
+
+                                  x
+                                   -
+                          1       | |  -t  a-1
+         igam(a,x)  =   -----     |   e   t   dt.
+                         -      | |
+                        | (a)    -
+                                  0
+
+
+        In this implementation both arguments must be positive.
+        The integral is evaluated by either a power series or
+        continued fraction expansion, depending on the relative
+        values of a and x.
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,30       200000       3.6e-14     2.9e-15
+           IEEE      0,100      300000       9.9e-14     1.5e-14
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1985, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double incompletegamma(double a,
+            double x)
+        {
+            double result = 0;
+            double igammaepsilon = 0;
+            double ans = 0;
+            double ax = 0;
+            double c = 0;
+            double r = 0;
+            double tmp = 0;
+
+            igammaepsilon = 0.000000000000001;
+            if( (double)(x)<=(double)(0) | (double)(a)<=(double)(0) )
+            {
+                result = 0;
+                return result;
+            }
+            if( (double)(x)>(double)(1) & (double)(x)>(double)(a) )
+            {
+                result = 1-incompletegammac(a, x);
+                return result;
+            }
+            ax = a*Math.Log(x)-x-gammafunc.lngamma(a, ref tmp);
+            if( (double)(ax)<(double)(-709.78271289338399) )
+            {
+                result = 0;
+                return result;
+            }
+            ax = Math.Exp(ax);
+            r = a;
+            c = 1;
+            ans = 1;
+            do
+            {
+                r = r+1;
+                c = c*x/r;
+                ans = ans+c;
+            }
+            while( (double)(c/ans)>(double)(igammaepsilon) );
+            result = ans*ax/a;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complemented incomplete gamma integral
+
+        The function is defined by
+
+
+         igamc(a,x)   =   1 - igam(a,x)
+
+                                   inf.
+                                     -
+                            1       | |  -t  a-1
+                      =   -----     |   e   t   dt.
+                           -      | |
+                          | (a)    -
+                                    x
+
+
+        In this implementation both arguments must be positive.
+        The integral is evaluated by either a power series or
+        continued fraction expansion, depending on the relative
+        values of a and x.
+
+        ACCURACY:
+
+        Tested at random a, x.
+                       a         x                      Relative error:
+        arithmetic   domain   domain     # trials      peak         rms
+           IEEE     0.5,100   0,100      200000       1.9e-14     1.7e-15
+           IEEE     0.01,0.5  0,100      200000       1.4e-13     1.6e-15
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1985, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double incompletegammac(double a,
+            double x)
+        {
+            double result = 0;
+            double igammaepsilon = 0;
+            double igammabignumber = 0;
+            double igammabignumberinv = 0;
+            double ans = 0;
+            double ax = 0;
+            double c = 0;
+            double yc = 0;
+            double r = 0;
+            double t = 0;
+            double y = 0;
+            double z = 0;
+            double pk = 0;
+            double pkm1 = 0;
+            double pkm2 = 0;
+            double qk = 0;
+            double qkm1 = 0;
+            double qkm2 = 0;
+            double tmp = 0;
+
+            igammaepsilon = 0.000000000000001;
+            igammabignumber = 4503599627370496.0;
+            igammabignumberinv = 2.22044604925031308085*0.0000000000000001;
+            if( (double)(x)<=(double)(0) | (double)(a)<=(double)(0) )
+            {
+                result = 1;
+                return result;
+            }
+            if( (double)(x)<(double)(1) | (double)(x)<(double)(a) )
+            {
+                result = 1-incompletegamma(a, x);
+                return result;
+            }
+            ax = a*Math.Log(x)-x-gammafunc.lngamma(a, ref tmp);
+            if( (double)(ax)<(double)(-709.78271289338399) )
+            {
+                result = 0;
+                return result;
+            }
+            ax = Math.Exp(ax);
+            y = 1-a;
+            z = x+y+1;
+            c = 0;
+            pkm2 = 1;
+            qkm2 = x;
+            pkm1 = x+1;
+            qkm1 = z*x;
+            ans = pkm1/qkm1;
+            do
+            {
+                c = c+1;
+                y = y+1;
+                z = z+2;
+                yc = y*c;
+                pk = pkm1*z-pkm2*yc;
+                qk = qkm1*z-qkm2*yc;
+                if( (double)(qk)!=(double)(0) )
+                {
+                    r = pk/qk;
+                    t = Math.Abs((ans-r)/r);
+                    ans = r;
+                }
+                else
+                {
+                    t = 1;
+                }
+                pkm2 = pkm1;
+                pkm1 = pk;
+                qkm2 = qkm1;
+                qkm1 = qk;
+                if( (double)(Math.Abs(pk))>(double)(igammabignumber) )
+                {
+                    pkm2 = pkm2*igammabignumberinv;
+                    pkm1 = pkm1*igammabignumberinv;
+                    qkm2 = qkm2*igammabignumberinv;
+                    qkm1 = qkm1*igammabignumberinv;
+                }
+            }
+            while( (double)(t)>(double)(igammaepsilon) );
+            result = ans*ax;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse of complemented imcomplete gamma integral
+
+        Given p, the function finds x such that
+
+         igamc( a, x ) = p.
+
+        Starting with the approximate value
+
+                3
+         x = a t
+
+         where
+
+         t = 1 - d - ndtri(p) sqrt(d)
+
+        and
+
+         d = 1/9a,
+
+        the routine performs up to 10 Newton iterations to find the
+        root of igamc(a,x) - p = 0.
+
+        ACCURACY:
+
+        Tested at random a, p in the intervals indicated.
+
+                       a        p                      Relative error:
+        arithmetic   domain   domain     # trials      peak         rms
+           IEEE     0.5,100   0,0.5       100000       1.0e-14     1.7e-15
+           IEEE     0.01,0.5  0,0.5       100000       9.0e-14     3.4e-15
+           IEEE    0.5,10000  0,0.5        20000       2.3e-13     3.8e-14
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invincompletegammac(double a,
+            double y0)
+        {
+            double result = 0;
+            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;
+
+            igammaepsilon = 0.000000000000001;
+            iinvgammabignumber = 4503599627370496.0;
+            x0 = iinvgammabignumber;
+            yl = 0;
+            x1 = 0;
+            yh = 1;
+            dithresh = 5*igammaepsilon;
+            d = 1/(9*a);
+            y = 1-d-normaldistr.invnormaldistribution(y0)*Math.Sqrt(d);
+            x = a*y*y*y;
+            lgm = gammafunc.lngamma(a, ref tmp);
+            i = 0;
+            while( i<10 )
+            {
+                if( (double)(x)>(double)(x0) | (double)(x)<(double)(x1) )
+                {
+                    d = 0.0625;
+                    break;
+                }
+                y = incompletegammac(a, x);
+                if( (double)(y)<(double)(yl) | (double)(y)>(double)(yh) )
+                {
+                    d = 0.0625;
+                    break;
+                }
+                if( (double)(y)<(double)(y0) )
+                {
+                    x0 = x;
+                    yl = y;
+                }
+                else
+                {
+                    x1 = x;
+                    yh = y;
+                }
+                d = (a-1)*Math.Log(x)-x-lgm;
+                if( (double)(d)<(double)(-709.78271289338399) )
+                {
+                    d = 0.0625;
+                    break;
+                }
+                d = -Math.Exp(d);
+                d = (y-y0)/d;
+                if( (double)(Math.Abs(d/x))<(double)(igammaepsilon) )
+                {
+                    result = x;
+                    return result;
+                }
+                x = x-d;
+                i = i+1;
+            }
+            if( (double)(x0)==(double)(iinvgammabignumber) )
+            {
+                if( (double)(x)<=(double)(0) )
+                {
+                    x = 1;
+                }
+                while( (double)(x0)==(double)(iinvgammabignumber) )
+                {
+                    x = (1+d)*x;
+                    y = incompletegammac(a, x);
+                    if( (double)(y)<(double)(y0) )
+                    {
+                        x0 = x;
+                        yl = y;
+                        break;
+                    }
+                    d = d+d;
+                }
+            }
+            d = 0.5;
+            dir = 0;
+            i = 0;
+            while( i<400 )
+            {
+                x = x1+d*(x0-x1);
+                y = incompletegammac(a, x);
+                lgm = (x0-x1)/(x1+x0);
+                if( (double)(Math.Abs(lgm))<(double)(dithresh) )
+                {
+                    break;
+                }
+                lgm = (y-y0)/y0;
+                if( (double)(Math.Abs(lgm))<(double)(dithresh) )
+                {
+                    break;
+                }
+                if( (double)(x)<=(double)(0.0) )
+                {
+                    break;
+                }
+                if( (double)(y)>=(double)(y0) )
+                {
+                    x1 = x;
+                    yh = y;
+                    if( dir<0 )
+                    {
+                        dir = 0;
+                        d = 0.5;
+                    }
+                    else
+                    {
+                        if( dir>1 )
+                        {
+                            d = 0.5*d+0.5;
+                        }
+                        else
+                        {
+                            d = (y0-yl)/(yh-yl);
+                        }
+                    }
+                    dir = dir+1;
+                }
+                else
+                {
+                    x0 = x;
+                    yl = y;
+                    if( dir>0 )
+                    {
+                        dir = 0;
+                        d = 0.5;
+                    }
+                    else
+                    {
+                        if( dir<-1 )
+                        {
+                            d = 0.5*d;
+                        }
+                        else
+                        {
+                            d = (y0-yl)/(yh-yl);
+                        }
+                    }
+                    dir = dir-1;
+                }
+                i = i+1;
+            }
+            result = x;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/inv.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/inv.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/inv.cs	(revision 2645)
@@ -0,0 +1,284 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee. All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class inv
+    {
+        /*************************************************************************
+        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 which were made during the LU decomposition
+                        (the output of RMatrixLU subroutine).
+            N       -   size of matrix A.
+
+        Output parameters:
+            A       -   inverse of matrix A.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular.
+
+          -- 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
+        *************************************************************************/
+        public static bool rmatrixluinverse(ref double[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            bool result = new bool();
+            double[] work = new double[0];
+            int i = 0;
+            int iws = 0;
+            int j = 0;
+            int jb = 0;
+            int jj = 0;
+            int jp = 0;
+            double v = 0;
+            int i_ = 0;
+
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            work = new double[n-1+1];
+            
+            //
+            // Form inv(U)
+            //
+            if( !trinverse.rmatrixtrinverse(ref a, n, true, false) )
+            {
+                result = false;
+                return result;
+            }
+            
+            //
+            // Solve the equation inv(A)*L = inv(U) for inv(A).
+            //
+            for(j=n-1; j>=0; j--)
+            {
+                
+                //
+                // Copy current column of L to WORK and replace with zeros.
+                //
+                for(i=j+1; i<=n-1; i++)
+                {
+                    work[i] = a[i,j];
+                    a[i,j] = 0;
+                }
+                
+                //
+                // Compute current column of inv(A).
+                //
+                if( j<n-1 )
+                {
+                    for(i=0; i<=n-1; i++)
+                    {
+                        v = 0.0;
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            v += a[i,i_]*work[i_];
+                        }
+                        a[i,j] = a[i,j]-v;
+                    }
+                }
+            }
+            
+            //
+            // Apply column interchanges.
+            //
+            for(j=n-2; j>=0; j--)
+            {
+                jp = pivots[j];
+                if( jp!=j )
+                {
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        work[i_] = a[i_,j];
+                    }
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        a[i_,j] = a[i_,jp];
+                    }
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        a[i_,jp] = work[i_];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inversion of a general matrix.
+
+        Input parameters:
+            A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
+            N   -   size of matrix A.
+
+        Output parameters:
+            A   -   inverse of matrix A.
+                    Array whose indexes range within [0..N-1, 0..N-1].
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool rmatrixinverse(ref double[,] a,
+            int n)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            lu.rmatrixlu(ref a, n, n, ref pivots);
+            result = rmatrixluinverse(ref a, ref pivots, n);
+            return result;
+        }
+
+
+        public static bool inverselu(ref double[,] a,
+            ref int[] pivots,
+            int n)
+        {
+            bool result = new bool();
+            double[] work = new double[0];
+            int i = 0;
+            int iws = 0;
+            int j = 0;
+            int jb = 0;
+            int jj = 0;
+            int jp = 0;
+            int jp1 = 0;
+            double v = 0;
+            int i_ = 0;
+
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            work = new double[n+1];
+            
+            //
+            // Form inv(U)
+            //
+            if( !trinverse.invtriangular(ref a, n, true, false) )
+            {
+                result = false;
+                return result;
+            }
+            
+            //
+            // Solve the equation inv(A)*L = inv(U) for inv(A).
+            //
+            for(j=n; j>=1; j--)
+            {
+                
+                //
+                // Copy current column of L to WORK and replace with zeros.
+                //
+                for(i=j+1; i<=n; i++)
+                {
+                    work[i] = a[i,j];
+                    a[i,j] = 0;
+                }
+                
+                //
+                // Compute current column of inv(A).
+                //
+                if( j<n )
+                {
+                    jp1 = j+1;
+                    for(i=1; i<=n; i++)
+                    {
+                        v = 0.0;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            v += a[i,i_]*work[i_];
+                        }
+                        a[i,j] = a[i,j]-v;
+                    }
+                }
+            }
+            
+            //
+            // Apply column interchanges.
+            //
+            for(j=n-1; j>=1; j--)
+            {
+                jp = pivots[j];
+                if( jp!=j )
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        work[i_] = a[i_,j];
+                    }
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        a[i_,j] = a[i_,jp];
+                    }
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        a[i_,jp] = work[i_];
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool inverse(ref double[,] a,
+            int n)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            lu.ludecomposition(ref a, n, n, ref pivots);
+            result = inverselu(ref a, ref pivots, n);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/inverseupdate.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/inverseupdate.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/inverseupdate.cs	(revision 2645)
@@ -0,0 +1,554 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class inverseupdate
+    {
+        /*************************************************************************
+        Inverse matrix update by the Sherman-Morrison formula
+
+        The algorithm updates matrix A^-1 when adding a number to an element
+        of matrix A.
+
+        Input parameters:
+            InvA    -   inverse of matrix A.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            UpdRow  -   row where the element to be updated is stored.
+            UpdColumn - column where the element to be updated is stored.
+            UpdVal  -   a number to be added to the element.
+
+
+        Output parameters:
+            InvA    -   inverse of modified matrix A.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixinvupdatesimple(ref double[,] inva,
+            int n,
+            int updrow,
+            int updcolumn,
+            double updval)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(updrow>=0 & updrow<n, "RMatrixInvUpdateSimple: incorrect UpdRow!");
+            System.Diagnostics.Debug.Assert(updcolumn>=0 & updcolumn<n, "RMatrixInvUpdateSimple: incorrect UpdColumn!");
+            t1 = new double[n-1+1];
+            t2 = new double[n-1+1];
+            
+            //
+            // T1 = InvA * U
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                t1[i_] = inva[i_,updrow];
+            }
+            
+            //
+            // T2 = v*InvA
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                t2[i_] = inva[updcolumn,i_];
+            }
+            
+            //
+            // Lambda = v * InvA * U
+            //
+            lambda = updval*inva[updcolumn,updrow];
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                vt = updval*t1[i];
+                vt = vt/(1+lambda);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Inverse matrix update by the Sherman-Morrison formula
+
+        The algorithm updates matrix A^-1 when adding a vector to a row
+        of matrix A.
+
+        Input parameters:
+            InvA    -   inverse of matrix A.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            UpdRow  -   the row of A whose vector V was added.
+                        0 <= Row <= N-1
+            V       -   the vector to be added to a row.
+                        Array whose index ranges within [0..N-1].
+
+        Output parameters:
+            InvA    -   inverse of modified matrix A.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixinvupdaterow(ref double[,] inva,
+            int n,
+            int updrow,
+            ref double[] v)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n-1+1];
+            t2 = new double[n-1+1];
+            
+            //
+            // T1 = InvA * U
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                t1[i_] = inva[i_,updrow];
+            }
+            
+            //
+            // T2 = v*InvA
+            // Lambda = v * InvA * U
+            //
+            for(j=0; j<=n-1; j++)
+            {
+                vt = 0.0;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    vt += v[i_]*inva[i_,j];
+                }
+                t2[j] = vt;
+            }
+            lambda = t2[updrow];
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                vt = t1[i]/(1+lambda);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Inverse matrix update by the Sherman-Morrison formula
+
+        The algorithm updates matrix A^-1 when adding a vector to a column
+        of matrix A.
+
+        Input parameters:
+            InvA        -   inverse of matrix A.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            N           -   size of matrix A.
+            UpdColumn   -   the column of A whose vector U was added.
+                            0 <= UpdColumn <= N-1
+            U           -   the vector to be added to a column.
+                            Array whose index ranges within [0..N-1].
+
+        Output parameters:
+            InvA        -   inverse of modified matrix A.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixinvupdatecolumn(ref double[,] inva,
+            int n,
+            int updcolumn,
+            ref double[] u)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n-1+1];
+            t2 = new double[n-1+1];
+            
+            //
+            // T1 = InvA * U
+            // Lambda = v * InvA * U
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                vt = 0.0;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    vt += inva[i,i_]*u[i_];
+                }
+                t1[i] = vt;
+            }
+            lambda = t1[updcolumn];
+            
+            //
+            // T2 = v*InvA
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                t2[i_] = inva[updcolumn,i_];
+            }
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                vt = t1[i]/(1+lambda);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Inverse matrix update by the Sherman-Morrison formula
+
+        The algorithm computes the inverse of matrix A+u*v by using the given matrix
+        A^-1 and the vectors u and v.
+
+        Input parameters:
+            InvA    -   inverse of matrix A.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            U       -   the vector modifying the matrix.
+                        Array whose index ranges within [0..N-1].
+            V       -   the vector modifying the matrix.
+                        Array whose index ranges within [0..N-1].
+
+        Output parameters:
+            InvA - inverse of matrix A + u*v'.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixinvupdateuv(ref double[,] inva,
+            int n,
+            ref double[] u,
+            ref double[] v)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n-1+1];
+            t2 = new double[n-1+1];
+            
+            //
+            // T1 = InvA * U
+            // Lambda = v * T1
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                vt = 0.0;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    vt += inva[i,i_]*u[i_];
+                }
+                t1[i] = vt;
+            }
+            lambda = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                lambda += v[i_]*t1[i_];
+            }
+            
+            //
+            // T2 = v*InvA
+            //
+            for(j=0; j<=n-1; j++)
+            {
+                vt = 0.0;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    vt += v[i_]*inva[i_,j];
+                }
+                t2[j] = vt;
+            }
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                vt = t1[i]/(1+lambda);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        public static void shermanmorrisonsimpleupdate(ref double[,] inva,
+            int n,
+            int updrow,
+            int updcolumn,
+            double updval)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n+1];
+            t2 = new double[n+1];
+            
+            //
+            // T1 = InvA * U
+            //
+            for(i_=1; i_<=n;i_++)
+            {
+                t1[i_] = inva[i_,updrow];
+            }
+            
+            //
+            // T2 = v*InvA
+            //
+            for(i_=1; i_<=n;i_++)
+            {
+                t2[i_] = inva[updcolumn,i_];
+            }
+            
+            //
+            // Lambda = v * InvA * U
+            //
+            lambda = updval*inva[updcolumn,updrow];
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=1; i<=n; i++)
+            {
+                vt = updval*t1[i];
+                vt = vt/(1+lambda);
+                for(i_=1; i_<=n;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        public static void shermanmorrisonupdaterow(ref double[,] inva,
+            int n,
+            int updrow,
+            ref double[] v)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n+1];
+            t2 = new double[n+1];
+            
+            //
+            // T1 = InvA * U
+            //
+            for(i_=1; i_<=n;i_++)
+            {
+                t1[i_] = inva[i_,updrow];
+            }
+            
+            //
+            // T2 = v*InvA
+            // Lambda = v * InvA * U
+            //
+            for(j=1; j<=n; j++)
+            {
+                vt = 0.0;
+                for(i_=1; i_<=n;i_++)
+                {
+                    vt += v[i_]*inva[i_,j];
+                }
+                t2[j] = vt;
+            }
+            lambda = t2[updrow];
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=1; i<=n; i++)
+            {
+                vt = t1[i]/(1+lambda);
+                for(i_=1; i_<=n;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        public static void shermanmorrisonupdatecolumn(ref double[,] inva,
+            int n,
+            int updcolumn,
+            ref double[] u)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n+1];
+            t2 = new double[n+1];
+            
+            //
+            // T1 = InvA * U
+            // Lambda = v * InvA * U
+            //
+            for(i=1; i<=n; i++)
+            {
+                vt = 0.0;
+                for(i_=1; i_<=n;i_++)
+                {
+                    vt += inva[i,i_]*u[i_];
+                }
+                t1[i] = vt;
+            }
+            lambda = t1[updcolumn];
+            
+            //
+            // T2 = v*InvA
+            //
+            for(i_=1; i_<=n;i_++)
+            {
+                t2[i_] = inva[updcolumn,i_];
+            }
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=1; i<=n; i++)
+            {
+                vt = t1[i]/(1+lambda);
+                for(i_=1; i_<=n;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+
+
+        public static void shermanmorrisonupdateuv(ref double[,] inva,
+            int n,
+            ref double[] u,
+            ref double[] v)
+        {
+            double[] t1 = new double[0];
+            double[] t2 = new double[0];
+            int i = 0;
+            int j = 0;
+            double lambda = 0;
+            double vt = 0;
+            int i_ = 0;
+
+            t1 = new double[n+1];
+            t2 = new double[n+1];
+            
+            //
+            // T1 = InvA * U
+            // Lambda = v * T1
+            //
+            for(i=1; i<=n; i++)
+            {
+                vt = 0.0;
+                for(i_=1; i_<=n;i_++)
+                {
+                    vt += inva[i,i_]*u[i_];
+                }
+                t1[i] = vt;
+            }
+            lambda = 0.0;
+            for(i_=1; i_<=n;i_++)
+            {
+                lambda += v[i_]*t1[i_];
+            }
+            
+            //
+            // T2 = v*InvA
+            //
+            for(j=1; j<=n; j++)
+            {
+                vt = 0.0;
+                for(i_=1; i_<=n;i_++)
+                {
+                    vt += v[i_]*inva[i_,j];
+                }
+                t2[j] = vt;
+            }
+            
+            //
+            // InvA = InvA - correction
+            //
+            for(i=1; i<=n; i++)
+            {
+                vt = t1[i]/(1+lambda);
+                for(i_=1; i_<=n;i_++)
+                {
+                    inva[i,i_] = inva[i,i_] - vt*t2[i_];
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/jacobianelliptic.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/jacobianelliptic.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/jacobianelliptic.cs	(revision 2645)
@@ -0,0 +1,154 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class jacobianelliptic
+    {
+        /*************************************************************************
+        Jacobian Elliptic Functions
+
+        Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m),
+        and dn(u|m) of parameter m between 0 and 1, and real
+        argument u.
+
+        These functions are periodic, with quarter-period on the
+        real axis equal to the complete elliptic integral
+        ellpk(1.0-m).
+
+        Relation to incomplete elliptic integral:
+        If u = ellik(phi,m), then sn(u|m) = sin(phi),
+        and cn(u|m) = cos(phi).  Phi is called the amplitude of u.
+
+        Computation is by means of the arithmetic-geometric mean
+        algorithm, except when m is within 1e-9 of 0 or 1.  In the
+        latter case with m close to 1, the approximation applies
+        only for phi < pi/2.
+
+        ACCURACY:
+
+        Tested at random points with u between 0 and 10, m between
+        0 and 1.
+
+                   Absolute error (* = relative error):
+        arithmetic   function   # trials      peak         rms
+           IEEE      phi         10000       9.2e-16*    1.4e-16*
+           IEEE      sn          50000       4.1e-15     4.6e-16
+           IEEE      cn          40000       3.6e-15     4.4e-16
+           IEEE      dn          10000       1.3e-12     1.8e-14
+
+         Peak error observed in consistency check using addition
+        theorem for sn(u+v) was 4e-16 (absolute).  Also tested by
+        the above relation to the incomplete elliptic integral.
+        Accuracy deteriorates when u is large.
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static void jacobianellipticfunctions(double u,
+            double m,
+            ref double sn,
+            ref double cn,
+            ref double dn,
+            ref double ph)
+        {
+            double ai = 0;
+            double b = 0;
+            double phi = 0;
+            double t = 0;
+            double twon = 0;
+            double[] a = new double[0];
+            double[] c = new double[0];
+            int i = 0;
+
+            System.Diagnostics.Debug.Assert((double)(m)>=(double)(0) & (double)(m)<=(double)(1), "Domain error in JacobianEllipticFunctions: m<0 or m>1");
+            a = new double[8+1];
+            c = new double[8+1];
+            if( (double)(m)<(double)(1.0e-9) )
+            {
+                t = Math.Sin(u);
+                b = Math.Cos(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;
+                return;
+            }
+            if( (double)(m)>=(double)(0.9999999999) )
+            {
+                ai = 0.25*(1.0-m);
+                b = Math.Cosh(u);
+                t = Math.Tanh(u);
+                phi = 1.0/b;
+                twon = b*Math.Sinh(u);
+                sn = t+ai*(twon-u)/(b*b);
+                ph = 2.0*Math.Atan(Math.Exp(u))-1.57079632679489661923+ai*(twon-u)/b;
+                ai = ai*t*phi;
+                cn = phi-ai*(twon-u);
+                dn = phi+ai*(twon+u);
+                return;
+            }
+            a[0] = 1.0;
+            b = Math.Sqrt(1.0-m);
+            c[0] = Math.Sqrt(m);
+            twon = 1.0;
+            i = 0;
+            while( (double)(Math.Abs(c[i]/a[i]))>(double)(AP.Math.MachineEpsilon) )
+            {
+                if( i>7 )
+                {
+                    System.Diagnostics.Debug.Assert(false, "Overflow in JacobianEllipticFunctions");
+                    break;
+                }
+                ai = a[i];
+                i = i+1;
+                c[i] = 0.5*(ai-b);
+                t = Math.Sqrt(ai*b);
+                a[i] = 0.5*(ai+b);
+                b = t;
+                twon = twon*2.0;
+            }
+            phi = twon*a[i]*u;
+            do
+            {
+                t = c[i]*Math.Sin(phi)/a[i];
+                b = phi;
+                phi = (Math.Asin(t)+phi)/2.0;
+                i = i-1;
+            }
+            while( i!=0 );
+            sn = Math.Sin(phi);
+            t = Math.Cos(phi);
+            cn = t;
+            dn = t/Math.Cos(phi-b);
+            ph = phi;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/jarquebera.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/jarquebera.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/jarquebera.cs	(revision 2645)
@@ -0,0 +1,2240 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class jarquebera
+    {
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 09.04.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void jarqueberatest(ref double[] x,
+            int n,
+            ref double p)
+        {
+            double s = 0;
+
+            
+            //
+            // N is too small
+            //
+            if( n<5 )
+            {
+                p = 1.0;
+                return;
+            }
+            
+            //
+            // N is large enough
+            //
+            jarqueberastatistic(ref x, n, ref s);
+            p = jarqueberaapprox(n, s);
+        }
+
+
+        private static void jarqueberastatistic(ref double[] x,
+            int n,
+            ref double s)
+        {
+            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 = 0;
+            variance = 0;
+            skewness = 0;
+            kurtosis = 0;
+            stddev = 0;
+            System.Diagnostics.Debug.Assert(n>1);
+            
+            //
+            // Mean
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                mean = mean+x[i];
+            }
+            mean = mean/n;
+            
+            //
+            // Variance (using corrected two-pass algorithm)
+            //
+            if( n!=1 )
+            {
+                v1 = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v1 = v1+AP.Math.Sqr(x[i]-mean);
+                }
+                v2 = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v2 = v2+(x[i]-mean);
+                }
+                v2 = AP.Math.Sqr(v2)/n;
+                variance = (v1-v2)/(n-1);
+                if( (double)(variance)<(double)(0) )
+                {
+                    variance = 0;
+                }
+                stddev = Math.Sqrt(variance);
+            }
+            
+            //
+            // Skewness and kurtosis
+            //
+            if( (double)(stddev)!=(double)(0) )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    v = (x[i]-mean)/stddev;
+                    v2 = AP.Math.Sqr(v);
+                    skewness = skewness+v2*v;
+                    kurtosis = kurtosis+AP.Math.Sqr(v2);
+                }
+                skewness = skewness/n;
+                kurtosis = kurtosis/n-3;
+            }
+            
+            //
+            // Statistic
+            //
+            s = (double)(n)/(double)(6)*(AP.Math.Sqr(skewness)+AP.Math.Sqr(kurtosis)/4);
+        }
+
+
+        private static double jarqueberaapprox(int n,
+            double s)
+        {
+            double result = 0;
+            double[] vx = new double[0];
+            double[] vy = new double[0];
+            double[,] ctbl = new double[0,0];
+            double t1 = 0;
+            double t2 = 0;
+            double t3 = 0;
+            double t = 0;
+            double f1 = 0;
+            double f2 = 0;
+            double f3 = 0;
+            double f = 0;
+            double f12 = 0;
+            double f23 = 0;
+            double x = 0;
+
+            result = 1;
+            x = s;
+            if( n<5 )
+            {
+                return result;
+            }
+            
+            //
+            // N = 5..20 are tabulated
+            //
+            if( n>=5 & n<=20 )
+            {
+                if( n==5 )
+                {
+                    result = Math.Exp(jbtbl5(x));
+                }
+                if( n==6 )
+                {
+                    result = Math.Exp(jbtbl6(x));
+                }
+                if( n==7 )
+                {
+                    result = Math.Exp(jbtbl7(x));
+                }
+                if( n==8 )
+                {
+                    result = Math.Exp(jbtbl8(x));
+                }
+                if( n==9 )
+                {
+                    result = Math.Exp(jbtbl9(x));
+                }
+                if( n==10 )
+                {
+                    result = Math.Exp(jbtbl10(x));
+                }
+                if( n==11 )
+                {
+                    result = Math.Exp(jbtbl11(x));
+                }
+                if( n==12 )
+                {
+                    result = Math.Exp(jbtbl12(x));
+                }
+                if( n==13 )
+                {
+                    result = Math.Exp(jbtbl13(x));
+                }
+                if( n==14 )
+                {
+                    result = Math.Exp(jbtbl14(x));
+                }
+                if( n==15 )
+                {
+                    result = Math.Exp(jbtbl15(x));
+                }
+                if( n==16 )
+                {
+                    result = Math.Exp(jbtbl16(x));
+                }
+                if( n==17 )
+                {
+                    result = Math.Exp(jbtbl17(x));
+                }
+                if( n==18 )
+                {
+                    result = Math.Exp(jbtbl18(x));
+                }
+                if( n==19 )
+                {
+                    result = Math.Exp(jbtbl19(x));
+                }
+                if( n==20 )
+                {
+                    result = Math.Exp(jbtbl20(x));
+                }
+                return result;
+            }
+            
+            //
+            // N = 20, 30, 50 are tabulated.
+            // In-between values are interpolated
+            // using interpolating polynomial of the second degree.
+            //
+            if( n>20 & n<=50 )
+            {
+                t1 = -(1.0/20.0);
+                t2 = -(1.0/30.0);
+                t3 = -(1.0/50.0);
+                t = -(1.0/n);
+                f1 = jbtbl20(x);
+                f2 = jbtbl30(x);
+                f3 = jbtbl50(x);
+                f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2);
+                f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3);
+                result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                result = Math.Exp(result);
+                return result;
+            }
+            
+            //
+            // N = 50, 65, 100 are tabulated.
+            // In-between values are interpolated
+            // using interpolating polynomial of the second degree.
+            //
+            if( n>50 & n<=100 )
+            {
+                t1 = -(1.0/50.0);
+                t2 = -(1.0/65.0);
+                t3 = -(1.0/100.0);
+                t = -(1.0/n);
+                f1 = jbtbl50(x);
+                f2 = jbtbl65(x);
+                f3 = jbtbl100(x);
+                f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2);
+                f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3);
+                result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                result = Math.Exp(result);
+                return result;
+            }
+            
+            //
+            // N = 100, 130, 200 are tabulated.
+            // In-between values are interpolated
+            // using interpolating polynomial of the second degree.
+            //
+            if( n>100 & n<=200 )
+            {
+                t1 = -(1.0/100.0);
+                t2 = -(1.0/130.0);
+                t3 = -(1.0/200.0);
+                t = -(1.0/n);
+                f1 = jbtbl100(x);
+                f2 = jbtbl130(x);
+                f3 = jbtbl200(x);
+                f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2);
+                f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3);
+                result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                result = Math.Exp(result);
+                return result;
+            }
+            
+            //
+            // N = 200, 301, 501 are tabulated.
+            // In-between values are interpolated
+            // using interpolating polynomial of the second degree.
+            //
+            if( n>200 & n<=501 )
+            {
+                t1 = -(1.0/200.0);
+                t2 = -(1.0/301.0);
+                t3 = -(1.0/501.0);
+                t = -(1.0/n);
+                f1 = jbtbl200(x);
+                f2 = jbtbl301(x);
+                f3 = jbtbl501(x);
+                f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2);
+                f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3);
+                result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                result = Math.Exp(result);
+                return result;
+            }
+            
+            //
+            // N = 501, 701, 1401 are tabulated.
+            // In-between values are interpolated
+            // using interpolating polynomial of the second degree.
+            //
+            if( n>501 & n<=1401 )
+            {
+                t1 = -(1.0/501.0);
+                t2 = -(1.0/701.0);
+                t3 = -(1.0/1401.0);
+                t = -(1.0/n);
+                f1 = jbtbl501(x);
+                f2 = jbtbl701(x);
+                f3 = jbtbl1401(x);
+                f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2);
+                f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3);
+                result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                result = Math.Exp(result);
+                return result;
+            }
+            
+            //
+            // Asymptotic expansion
+            //
+            if( n>1401 )
+            {
+                result = -(0.5*x)+(jbtbl1401(x)+0.5*x)*Math.Sqrt((double)(1401)/(double)(n));
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                result = Math.Exp(result);
+                return result;
+            }
+            return result;
+        }
+
+
+        private static double jbtbl5(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(0.4000) )
+            {
+                x = 2*(s-0.000000)/0.400000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.097885e-20, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.854501e-20, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.756616e-20, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(1.1000) )
+            {
+                x = 2*(s-0.400000)/0.700000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.324545e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.075941e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.772272e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.175686e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.576162e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.126861e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.434425e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.790359e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.809178e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.479704e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.717040e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.294170e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.880632e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.023344e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.601531e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.920403e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(5.188419e+02*(s-1.100000e+00))-4.767297e+00;
+            return result;
+        }
+
+
+        private static double jbtbl6(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(0.2500) )
+            {
+                x = 2*(s-0.000000)/0.250000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.274707e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.700471e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.425764e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(1.3000) )
+            {
+                x = 2*(s-0.250000)/1.050000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.339000e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.011104e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.168177e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.085666e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.738606e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.022876e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.462402e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.908270e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.230772e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.006996e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.410222e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.893768e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.114564e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(1.8500) )
+            {
+                x = 2*(s-1.300000)/0.550000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.794311e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.578700e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.394664e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.928290e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.813273e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.076063e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.835380e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.013013e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.058903e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.856915e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.710887e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.770029e+02*(s-1.850000e+00))-1.371015e+01;
+            return result;
+        }
+
+
+        private static double jbtbl7(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.4000) )
+            {
+                x = 2*(s-0.000000)/1.400000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.093681e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.695911e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.473192e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.203236e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.590379e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.291876e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.132007e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.411147e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.180067e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.487610e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.436561e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-1.400000)/1.600000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.947854e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.772675e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.707912e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.691171e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.132795e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.481310e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.867536e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.772327e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.033387e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.378277e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.497964e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.636814e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.581640e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(3.2000) )
+            {
+                x = 2*(s-3.000000)/0.200000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -7.511008e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.140472e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.682053e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.568561e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.933930e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.140472e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.895025e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.140472e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.933930e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.568561e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.682053e+00, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.824116e+03*(s-3.200000e+00))-1.440330e+01;
+            return result;
+        }
+
+
+        private static double jbtbl8(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.3000) )
+            {
+                x = 2*(s-0.000000)/1.300000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -7.199015e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.095921e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.736828e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.047438e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.484320e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.937923e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.810470e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.139780e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.708443e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(2.0000) )
+            {
+                x = 2*(s-1.300000)/0.700000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -3.378966e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.802461e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.547593e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.241042e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.203274e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.201990e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.125597e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.584426e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.546069e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(5.0000) )
+            {
+                x = 2*(s-2.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.828366e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.137533e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.016671e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.745637e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.189801e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.621610e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.741122e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.516368e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.552085e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.787029e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.359774e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(5.087028e+00*(s-5.000000e+00))-1.071300e+01;
+            return result;
+        }
+
+
+        private static double jbtbl9(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.3000) )
+            {
+                x = 2*(s-0.000000)/1.300000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.279320e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.277151e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.669339e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.086149e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.333816e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.871249e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.007048e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.482245e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.355615e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(2.0000) )
+            {
+                x = 2*(s-1.300000)/0.700000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.981430e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.972248e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.747737e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.808530e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.888305e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.001302e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.378767e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.108510e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.915372e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(7.0000) )
+            {
+                x = 2*(s-2.000000)/5.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.387463e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.845231e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.809956e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.543461e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.880397e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.160074e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.356527e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.394428e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.619892e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.758763e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.790977e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.020952e+00*(s-7.000000e+00))-9.516623e+00;
+            return result;
+        }
+
+
+        private static double jbtbl10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.2000) )
+            {
+                x = 2*(s-0.000000)/1.200000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.590993e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.562730e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.353934e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.069933e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.849151e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.931406e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.636295e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.178340e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.917749e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(2.0000) )
+            {
+                x = 2*(s-1.200000)/0.800000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.537658e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.962401e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.838715e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.055792e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.580316e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.781701e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.770362e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.838983e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.999052e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(7.0000) )
+            {
+                x = 2*(s-2.000000)/5.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.337524e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.877029e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.734650e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.249254e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.320250e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.432266e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(8.711035e-01*(s-7.000000e+00))-7.212811e+00;
+            return result;
+        }
+
+
+        private static double jbtbl11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.2000) )
+            {
+                x = 2*(s-0.000000)/1.200000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.339517e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.051558e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.000992e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.022547e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.808401e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.592870e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.575081e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.086173e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.089011e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(2.2500) )
+            {
+                x = 2*(s-1.200000)/1.050000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.523221e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.068388e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.179661e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.555524e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.238964e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.364320e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.895771e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.762774e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.201340e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(8.0000) )
+            {
+                x = 2*(s-2.250000)/5.750000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.212179e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.684579e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.299519e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.606261e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.310869e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.320115e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(5.715445e-01*(s-8.000000e+00))-6.845834e+00;
+            return result;
+        }
+
+
+        private static double jbtbl12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.0000) )
+            {
+                x = 2*(s-0.000000)/1.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.736742e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.657836e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.047209e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.319599e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.545631e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.280445e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.815679e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.213519e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.256838e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-1.000000)/2.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.573947e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.515287e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.611880e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.271311e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.495815e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.141186e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.180886e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.388211e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.890761e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.233175e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.946156e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(12.0000) )
+            {
+                x = 2*(s-3.000000)/9.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.947819e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.034157e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.878986e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.078603e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.990977e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.866215e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.897866e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.512252e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.073743e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.022621e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.501343e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.877243e-01*(s-1.200000e+01))-7.936839e+00;
+            return result;
+        }
+
+
+        private static double jbtbl13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.0000) )
+            {
+                x = 2*(s-0.000000)/1.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.713276e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.557541e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.459092e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.044145e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.546132e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.002374e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.349456e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.025669e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.590242e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-1.000000)/2.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.454383e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.467539e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.270774e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.075763e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.611647e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.990785e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.109212e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.135031e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.915919e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.522390e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.144701e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(13.0000) )
+            {
+                x = 2*(s-3.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.736127e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.920809e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.175858e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.002049e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.158966e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.157781e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.762172e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.780347e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.193310e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.442421e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.547756e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.799944e-01*(s-1.300000e+01))-7.566269e+00;
+            return result;
+        }
+
+
+        private static double jbtbl14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(1.0000) )
+            {
+                x = 2*(s-0.000000)/1.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.698527e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.479081e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.640733e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.466899e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.469485e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.150009e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.965975e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.710210e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.327808e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-1.000000)/2.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -2.350359e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.421365e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.960468e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.149167e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.361109e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.976022e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.082700e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.563328e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.453123e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.917559e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.151067e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-3.000000)/12.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.746892e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.010441e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.566146e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.129690e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.929724e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.524227e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.192933e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.254730e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.620685e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.289618e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.112350e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.590621e-01*(s-1.500000e+01))-7.632238e+00;
+            return result;
+        }
+
+
+        private static double jbtbl15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(2.0000) )
+            {
+                x = 2*(s-0.000000)/2.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.043660e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.361653e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.009497e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.951784e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.377903e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.003253e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.271309e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(5.0000) )
+            {
+                x = 2*(s-2.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -3.582778e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.349578e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.476514e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.717385e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.222591e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.635124e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.815993e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(17.0000) )
+            {
+                x = 2*(s-5.000000)/12.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.115476e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.655936e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.404310e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.663794e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.868618e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.381447e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.444801e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.581503e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.468696e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.728509e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.206470e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.927937e-01*(s-1.700000e+01))-7.700983e+00;
+            return result;
+        }
+
+
+        private static double jbtbl16(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(2.0000) )
+            {
+                x = 2*(s-0.000000)/2.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.002570e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.298141e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.832803e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.877026e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.539436e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.439658e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.756911e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(5.0000) )
+            {
+                x = 2*(s-2.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -3.486198e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.242944e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.020002e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.130531e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.512373e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.054876e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.556839e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(20.0000) )
+            {
+                x = 2*(s-5.000000)/15.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.241608e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.832655e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.340545e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.361143e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.283219e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.484549e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.805968e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.057243e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.454439e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.177513e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.819209e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.391580e-01*(s-2.000000e+01))-7.963205e+00;
+            return result;
+        }
+
+
+        private static double jbtbl17(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-0.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.566973e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.810330e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.840039e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.337294e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.383549e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.556515e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.656965e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.404569e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.447867e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(6.0000) )
+            {
+                x = 2*(s-3.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -3.905684e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.222920e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.146667e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.809176e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.057028e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.211838e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.099683e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.161105e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.225465e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(24.0000) )
+            {
+                x = 2*(s-6.000000)/18.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.594282e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.917838e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.455980e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.999589e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.604263e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.484445e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.819937e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.930390e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.771761e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.232581e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.029083e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.127771e-01*(s-2.400000e+01))-8.400197e+00;
+            return result;
+        }
+
+
+        private static double jbtbl18(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-0.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.526802e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.762373e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.598890e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.189437e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.971721e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.823067e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.064501e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.014932e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.953513e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(6.0000) )
+            {
+                x = 2*(s-3.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -3.818669e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.070918e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.277196e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.879817e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.887357e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.638451e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.502800e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.165796e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.034960e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(20.0000) )
+            {
+                x = 2*(s-6.000000)/14.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.010656e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.496296e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.002227e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.338250e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.137036e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.586202e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.736384e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.332251e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.877982e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.160963e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.547247e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.684623e-01*(s-2.000000e+01))-7.428883e+00;
+            return result;
+        }
+
+
+        private static double jbtbl19(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(3.0000) )
+            {
+                x = 2*(s-0.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.490213e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.719633e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.459123e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.034878e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.113868e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.030922e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.054022e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.525623e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.277360e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(6.0000) )
+            {
+                x = 2*(s-3.000000)/3.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -3.744750e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.977749e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.223716e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.363889e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.711774e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.557257e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.254794e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.034207e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.498107e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(20.0000) )
+            {
+                x = 2*(s-6.000000)/14.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.872768e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.430689e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.136575e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.726627e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.421110e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.581510e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.559520e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.838208e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.428839e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.170682e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.006647e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.539373e-01*(s-2.000000e+01))-7.206941e+00;
+            return result;
+        }
+
+
+        private static double jbtbl20(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.854794e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.948947e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.632184e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.139397e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.006237e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.810031e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.573620e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.951242e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.274092e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.464196e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.882139e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.575144e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.822804e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.061348e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.908404e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.978353e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.030989e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.327151e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.346404e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.840051e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.578551e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.813886e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.905973e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.358489e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.450795e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.941157e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.432418e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.070537e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.375654e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.367378e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.890859e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.679782e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -7.015854e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.487737e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.244254e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.318007e-01*(s-2.500000e+01))-7.742185e+00;
+            return result;
+        }
+
+
+        private static double jbtbl30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.630822e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.724298e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.872756e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.658268e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.573597e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.994157e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.994825e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.394303e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.785029e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.990264e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.037838e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.755546e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.774473e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.821395e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.392603e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.353313e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.539322e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.197018e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.396848e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.804293e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.867928e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.768758e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.211792e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.925799e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.046235e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.536469e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.489642e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.263462e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.177316e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.590637e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.028212e-01*(s-2.500000e+01))-6.855288e+00;
+            return result;
+        }
+
+
+        private static double jbtbl50(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.436279e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.519711e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.148699e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.001204e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.207620e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.034778e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.220322e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.033260e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.588280e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.851653e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.287733e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.234645e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.189127e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.429738e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.058822e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 9.086776e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.445783e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.311671e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.261298e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.496987e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.605249e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.162282e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.921095e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.888603e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.080113e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(9.313116e-02*(s-2.500000e+01))-6.479154e+00;
+            return result;
+        }
+
+
+        private static double jbtbl65(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.360024e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.434631e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.514580e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 7.332038e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.158197e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.121233e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.051056e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.148601e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.214233e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.487977e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.424720e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.116715e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.043152e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.718149e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.313701e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.097305e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.181031e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.256975e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.858951e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.895179e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.933237e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(9.443768e-02*(s-2.500000e+01))-6.419137e+00;
+            return result;
+        }
+
+
+        private static double jbtbl100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.257021e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.313418e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.628931e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.264287e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.518487e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.499826e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.836044e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.056508e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.279690e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.665746e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.290012e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.487632e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.704465e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.211669e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.866099e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.399767e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.498208e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.080097e-01*(s-2.500000e+01))-6.481094e+00;
+            return result;
+        }
+
+
+        private static double jbtbl130(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.207999e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.253864e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.618032e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.112729e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.210546e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.732602e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.410527e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.026324e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.331990e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.779129e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.674749e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.669077e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.679136e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 8.833221e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -5.893951e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.475304e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.116734e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.045722e-01*(s-2.500000e+01))-6.510314e+00;
+            return result;
+        }
+
+
+        private static double jbtbl200(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.146155e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.177398e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.297970e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.869745e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.717288e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.982108e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.427636e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.034235e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.455006e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.942996e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.973795e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.418812e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.156778e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.896705e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.086071e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.152176e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.725393e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.132404e-01*(s-2.500000e+01))-6.764034e+00;
+            return result;
+        }
+
+
+        private static double jbtbl301(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.104290e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.125800e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.595847e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.219666e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.502210e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.414543e-05, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.754115e-05, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.065955e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.582060e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.004472e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -4.709092e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.105779e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.197391e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.386780e-04, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.311384e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.918763e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.626584e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.293626e-01*(s-2.500000e+01))-7.066995e+00;
+            return result;
+        }
+
+
+        private static double jbtbl501(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.067426e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.079765e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -5.463005e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 6.875659e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.127574e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.740694e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.044502e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.746714e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, 3.810594e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.197111e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.628194e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -8.846221e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.386405e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.418332e-01*(s-2.500000e+01))-7.468952e+00;
+            return result;
+        }
+
+
+        private static double jbtbl701(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.050999e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.059769e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -3.922680e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 4.847054e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.192182e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.860007e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.963942e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.838711e-02, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.893112e-04, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.159788e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -6.917851e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -9.817020e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.383727e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(1.532706e-01*(s-2.500000e+01))-7.845715e+00;
+            return result;
+        }
+
+
+        private static double jbtbl1401(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            if( (double)(s)<=(double)(4.0000) )
+            {
+                x = 2*(s-0.000000)/4.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -1.026266e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.030061e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.259222e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, 2.536254e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(15.0000) )
+            {
+                x = 2*(s-4.000000)/11.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -4.329849e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -2.095443e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 1.759363e-01, ref tj, ref tj1, ref result);
+                jbcheb(x, -7.751359e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -6.124368e-03, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.793114e-03, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            if( (double)(s)<=(double)(25.0000) )
+            {
+                x = 2*(s-15.000000)/10.000000-1;
+                tj = 1;
+                tj1 = x;
+                jbcheb(x, -7.544330e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, -1.225382e+00, ref tj, ref tj1, ref result);
+                jbcheb(x, 5.392349e-02, ref tj, ref tj1, ref result);
+                if( (double)(result)>(double)(0) )
+                {
+                    result = 0;
+                }
+                return result;
+            }
+            result = -(2.019375e-01*(s-2.500000e+01))-8.715788e+00;
+            return result;
+        }
+
+
+        private static void jbcheb(double x,
+            double c,
+            ref double tj,
+            ref double tj1,
+            ref double r)
+        {
+            double t = 0;
+
+            r = r+c*tj;
+            t = 2*x*tj1-tj;
+            tj = tj1;
+            tj1 = t;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/kmeans.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/kmeans.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/kmeans.cs	(revision 2645)
@@ -0,0 +1,385 @@
+/*************************************************************************
+Copyright (c) 2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class kmeans
+    {
+        /*************************************************************************
+        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 taskis 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 which contains number of clusters dataset points
+                            belong to.
+
+          -- ALGLIB --
+             Copyright 21.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void kmeansgenerate(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int k,
+            int restarts,
+            ref int info,
+            ref double[,] c,
+            ref int[] xyc)
+        {
+            int i = 0;
+            int j = 0;
+            double[,] ct = new double[0,0];
+            double[,] ctbest = new double[0,0];
+            double e = 0;
+            double ebest = 0;
+            double[] x = new double[0];
+            double[] tmp = new double[0];
+            int cc = 0;
+            double[] d2 = new double[0];
+            double[] p = new double[0];
+            int[] csizes = new int[0];
+            bool[] cbusy = new bool[0];
+            double v = 0;
+            double s = 0;
+            int cclosest = 0;
+            double dclosest = 0;
+            double[] work = new double[0];
+            bool waschanges = new bool();
+            bool zerosizeclusters = new bool();
+            int pass = 0;
+            int i_ = 0;
+
+            
+            //
+            // Test parameters
+            //
+            if( npoints<k | nvars<1 | k<1 | restarts<1 )
+            {
+                info = -1;
+                return;
+            }
+            
+            //
+            // TODO: special case K=1
+            // TODO: special case K=NPoints
+            //
+            info = 1;
+            
+            //
+            // Multiple passes of k-means++ algorithm
+            //
+            ct = new double[k-1+1, nvars-1+1];
+            ctbest = new double[k-1+1, nvars-1+1];
+            xyc = new int[npoints-1+1];
+            d2 = new double[npoints-1+1];
+            p = new double[npoints-1+1];
+            tmp = new double[nvars-1+1];
+            csizes = new int[k-1+1];
+            cbusy = new bool[k-1+1];
+            ebest = AP.Math.MaxRealNumber;
+            for(pass=1; pass<=restarts; pass++)
+            {
+                
+                //
+                // Select initial centers  using k-means++ algorithm
+                // 1. Choose first center at random
+                // 2. Choose next centers using their distance from centers already chosen
+                //
+                // Note that for performance reasons centers are stored in ROWS of CT, not
+                // in columns. We'll transpose CT in the end and store it in the C.
+                //
+                i = AP.Math.RandomInteger(npoints);
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    ct[0,i_] = xy[i,i_];
+                }
+                cbusy[0] = true;
+                for(i=1; i<=k-1; i++)
+                {
+                    cbusy[i] = false;
+                }
+                if( !selectcenterpp(ref xy, npoints, nvars, ref ct, cbusy, k, ref d2, ref p, ref tmp) )
+                {
+                    info = -3;
+                    return;
+                }
+                
+                //
+                // Update centers:
+                // 2. update center positions
+                //
+                while( true )
+                {
+                    
+                    //
+                    // fill XYC with center numbers
+                    //
+                    waschanges = false;
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        cclosest = -1;
+                        dclosest = AP.Math.MaxRealNumber;
+                        for(j=0; j<=k-1; j++)
+                        {
+                            for(i_=0; i_<=nvars-1;i_++)
+                            {
+                                tmp[i_] = xy[i,i_];
+                            }
+                            for(i_=0; i_<=nvars-1;i_++)
+                            {
+                                tmp[i_] = tmp[i_] - ct[j,i_];
+                            }
+                            v = 0.0;
+                            for(i_=0; i_<=nvars-1;i_++)
+                            {
+                                v += tmp[i_]*tmp[i_];
+                            }
+                            if( (double)(v)<(double)(dclosest) )
+                            {
+                                cclosest = j;
+                                dclosest = v;
+                            }
+                        }
+                        if( xyc[i]!=cclosest )
+                        {
+                            waschanges = true;
+                        }
+                        xyc[i] = cclosest;
+                    }
+                    
+                    //
+                    // Update centers
+                    //
+                    for(j=0; j<=k-1; j++)
+                    {
+                        csizes[j] = 0;
+                    }
+                    for(i=0; i<=k-1; i++)
+                    {
+                        for(j=0; j<=nvars-1; j++)
+                        {
+                            ct[i,j] = 0;
+                        }
+                    }
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        csizes[xyc[i]] = csizes[xyc[i]]+1;
+                        for(i_=0; i_<=nvars-1;i_++)
+                        {
+                            ct[xyc[i],i_] = ct[xyc[i],i_] + xy[i,i_];
+                        }
+                    }
+                    zerosizeclusters = false;
+                    for(i=0; i<=k-1; i++)
+                    {
+                        cbusy[i] = csizes[i]!=0;
+                        zerosizeclusters = zerosizeclusters | csizes[i]==0;
+                    }
+                    if( zerosizeclusters )
+                    {
+                        
+                        //
+                        // Some clusters have zero size - rare, but possible.
+                        // We'll choose new centers for such clusters using k-means++ rule
+                        // and restart algorithm
+                        //
+                        if( !selectcenterpp(ref xy, npoints, nvars, ref ct, cbusy, k, ref d2, ref p, ref tmp) )
+                        {
+                            info = -3;
+                            return;
+                        }
+                        continue;
+                    }
+                    for(j=0; j<=k-1; j++)
+                    {
+                        v = (double)(1)/(double)(csizes[j]);
+                        for(i_=0; i_<=nvars-1;i_++)
+                        {
+                            ct[j,i_] = v*ct[j,i_];
+                        }
+                    }
+                    
+                    //
+                    // if nothing has changed during iteration
+                    //
+                    if( !waschanges )
+                    {
+                        break;
+                    }
+                }
+                
+                //
+                // 3. Calculate E, compare with best centers found so far
+                //
+                e = 0;
+                for(i=0; i<=npoints-1; i++)
+                {
+                    for(i_=0; i_<=nvars-1;i_++)
+                    {
+                        tmp[i_] = xy[i,i_];
+                    }
+                    for(i_=0; i_<=nvars-1;i_++)
+                    {
+                        tmp[i_] = tmp[i_] - ct[xyc[i],i_];
+                    }
+                    v = 0.0;
+                    for(i_=0; i_<=nvars-1;i_++)
+                    {
+                        v += tmp[i_]*tmp[i_];
+                    }
+                    e = e+v;
+                }
+                if( (double)(e)<(double)(ebest) )
+                {
+                    
+                    //
+                    // store partition
+                    //
+                    blas.copymatrix(ref ct, 0, k-1, 0, nvars-1, ref ctbest, 0, k-1, 0, nvars-1);
+                }
+            }
+            
+            //
+            // Copy and transpose
+            //
+            c = new double[nvars-1+1, k-1+1];
+            blas.copyandtranspose(ref ctbest, 0, k-1, 0, nvars-1, ref c, 0, nvars-1, 0, k-1);
+        }
+
+
+        /*************************************************************************
+        Select center for a new cluster using k-means++ rule
+        *************************************************************************/
+        private static bool selectcenterpp(ref double[,] xy,
+            int npoints,
+            int nvars,
+            ref double[,] centers,
+            bool[] busycenters,
+            int ccnt,
+            ref double[] d2,
+            ref double[] p,
+            ref double[] tmp)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            int cc = 0;
+            double v = 0;
+            double s = 0;
+            int i_ = 0;
+
+            busycenters = (bool[])busycenters.Clone();
+
+            result = true;
+            for(cc=0; cc<=ccnt-1; cc++)
+            {
+                if( !busycenters[cc] )
+                {
+                    
+                    //
+                    // fill D2
+                    //
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        d2[i] = AP.Math.MaxRealNumber;
+                        for(j=0; j<=ccnt-1; j++)
+                        {
+                            if( busycenters[j] )
+                            {
+                                for(i_=0; i_<=nvars-1;i_++)
+                                {
+                                    tmp[i_] = xy[i,i_];
+                                }
+                                for(i_=0; i_<=nvars-1;i_++)
+                                {
+                                    tmp[i_] = tmp[i_] - centers[j,i_];
+                                }
+                                v = 0.0;
+                                for(i_=0; i_<=nvars-1;i_++)
+                                {
+                                    v += tmp[i_]*tmp[i_];
+                                }
+                                if( (double)(v)<(double)(d2[i]) )
+                                {
+                                    d2[i] = v;
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // calculate P (non-cumulative)
+                    //
+                    s = 0;
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        s = s+d2[i];
+                    }
+                    if( (double)(s)==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    s = 1/s;
+                    for(i_=0; i_<=npoints-1;i_++)
+                    {
+                        p[i_] = s*d2[i_];
+                    }
+                    
+                    //
+                    // choose one of points with probability P
+                    // random number within (0,1) is generated and
+                    // inverse empirical CDF is used to randomly choose a point.
+                    //
+                    s = 0;
+                    v = AP.Math.RandomReal();
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        s = s+p[i];
+                        if( (double)(v)<=(double)(s) | i==npoints-1 )
+                        {
+                            for(i_=0; i_<=nvars-1;i_++)
+                            {
+                                centers[cc,i_] = xy[i,i_];
+                            }
+                            busycenters[cc] = true;
+                            break;
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/laguerre.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/laguerre.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/laguerre.cs	(revision 2645)
@@ -0,0 +1,117 @@
+/*************************************************************************
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class laguerre
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static double laguerrecalculate(int n,
+            double x)
+        {
+            double result = 0;
+            double a = 0;
+            double b = 0;
+            double i = 0;
+
+            result = 1;
+            a = 1;
+            b = 1-x;
+            if( n==1 )
+            {
+                result = b;
+            }
+            i = 2;
+            while( (double)(i)<=(double)(n) )
+            {
+                result = ((2*i-1-x)*b-(i-1)*a)/i;
+                a = b;
+                b = result;
+                i = i+1;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Summation of Laguerre polynomials using Clenshaws recurrence formula.
+
+        This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x)
+
+        Parameters:
+            n   -   degree, n>=0
+            x   -   argument
+
+        Result:
+            the value of the Laguerre polynomial at x
+        *************************************************************************/
+        public static double laguerresum(ref double[] c,
+            int n,
+            double x)
+        {
+            double result = 0;
+            double b1 = 0;
+            double b2 = 0;
+            int i = 0;
+
+            b1 = 0;
+            b2 = 0;
+            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;
+        }
+
+
+        /*************************************************************************
+        Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N
+
+        Input parameters:
+            N   -   polynomial degree, n>=0
+
+        Output parameters:
+            C   -   coefficients
+        *************************************************************************/
+        public static void laguerrecoefficients(int n,
+            ref double[] c)
+        {
+            int i = 0;
+
+            c = new double[n+1];
+            c[0] = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                c[i+1] = -(c[i]*(n-i)/(i+1)/(i+1));
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lbfgs.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lbfgs.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lbfgs.cs	(revision 2645)
@@ -0,0 +1,1287 @@
+/*************************************************************************
+Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class lbfgs
+    {
+        public struct lbfgsstate
+        {
+            public int n;
+            public int m;
+            public double epsg;
+            public double epsf;
+            public double epsx;
+            public int maxits;
+            public int flags;
+            public int nfev;
+            public int mcstage;
+            public int k;
+            public int q;
+            public int p;
+            public double[] rho;
+            public double[,] y;
+            public double[,] s;
+            public double[] theta;
+            public double[] d;
+            public double stp;
+            public double[] work;
+            public double fold;
+            public double gammak;
+            public double[] x;
+            public double f;
+            public double[] g;
+            public bool xupdated;
+            public AP.rcommstate rstate;
+            public int repiterationscount;
+            public int repnfev;
+            public int repterminationtype;
+            public bool brackt;
+            public bool stage1;
+            public int infoc;
+            public double dg;
+            public double dgm;
+            public double dginit;
+            public double dgtest;
+            public double dgx;
+            public double dgxm;
+            public double dgy;
+            public double dgym;
+            public double finit;
+            public double ftest1;
+            public double fm;
+            public double fx;
+            public double fxm;
+            public double fy;
+            public double fym;
+            public double stx;
+            public double sty;
+            public double stmin;
+            public double stmax;
+            public double width;
+            public double width1;
+            public double xtrapf;
+        };
+
+
+        public struct lbfgsreport
+        {
+            public int iterationscount;
+            public int nfev;
+            public int terminationtype;
+        };
+
+
+
+
+        public const double ftol = 0.0001;
+        public const double xtol = 100*AP.Math.MachineEpsilon;
+        public const double gtol = 0.9;
+        public const int maxfev = 20;
+        public const double stpmin = 1.0E-20;
+        public const double stpmax = 1.0E20;
+
+
+        /*************************************************************************
+                LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION
+
+        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.
+
+        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].
+            EpsG -  positive number which  defines  a  precision  of  search.  The
+                    subroutine finishes its work if the condition ||G|| < EpsG  is
+                    satisfied, where ||.|| means Euclidian norm, G - gradient, X -
+                    current approximation.
+            EpsF -  positive number which  defines  a  precision  of  search.  The
+                    subroutine finishes its work if on iteration  number  k+1  the
+                    condition |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}    is
+                    satisfied.
+            EpsX -  positive number which  defines  a  precision  of  search.  The
+                    subroutine finishes its work if on iteration number k+1    the
+                    condition |X(k+1)-X(k)| <= EpsX is fulfilled.
+            MaxIts- maximum number of iterations. If MaxIts=0, the number of
+                    iterations is unlimited.
+            Flags - additional settings:
+                    * Flags = 0     means no additional settings
+                    * Flags = 1     "do not allocate memory". used when solving
+                                    a many subsequent tasks with  same N/M  values.
+                                    First  call MUST  be without this flag bit set,
+                                    subsequent calls of MinLBFGS with same LBFGSState
+                                    structure can set Flags to 1.
+
+        Output parameters:
+            State - structure used for reverse communication.
+            
+        See also MinLBFGSIteration, MinLBFGSResults
+
+          -- ALGLIB --
+             Copyright 14.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void minlbfgs(int n,
+            int m,
+            ref double[] x,
+            double epsg,
+            double epsf,
+            double epsx,
+            int maxits,
+            int flags,
+            ref lbfgsstate state)
+        {
+            bool allocatemem = new bool();
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "MinLBFGS: N too small!");
+            System.Diagnostics.Debug.Assert(m>=1, "MinLBFGS: M too small!");
+            System.Diagnostics.Debug.Assert(m<=n, "MinLBFGS: M too large!");
+            System.Diagnostics.Debug.Assert((double)(epsg)>=(double)(0), "MinLBFGS: negative EpsG!");
+            System.Diagnostics.Debug.Assert((double)(epsf)>=(double)(0), "MinLBFGS: negative EpsF!");
+            System.Diagnostics.Debug.Assert((double)(epsx)>=(double)(0), "MinLBFGS: negative EpsX!");
+            System.Diagnostics.Debug.Assert(maxits>=0, "MinLBFGS: negative MaxIts!");
+            
+            //
+            // Initialize
+            //
+            state.n = n;
+            state.m = m;
+            state.epsg = epsg;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.flags = flags;
+            allocatemem = flags%2==0;
+            flags = flags/2;
+            if( allocatemem )
+            {
+                state.rho = new double[m-1+1];
+                state.theta = new double[m-1+1];
+                state.y = new double[m-1+1, n-1+1];
+                state.s = new double[m-1+1, n-1+1];
+                state.d = new double[n-1+1];
+                state.x = new double[n-1+1];
+                state.g = new double[n-1+1];
+                state.work = new double[n-1+1];
+            }
+            
+            //
+            // Initialize Rep structure
+            //
+            state.xupdated = false;
+            
+            //
+            // Prepare first run
+            //
+            state.k = 0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.x[i_] = x[i_];
+            }
+            state.rstate.ia = new int[6+1];
+            state.rstate.ra = new double[4+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        One L-BFGS iteration
+
+        Called after initialization with MinLBFGS.
+        See HTML documentation for examples.
+
+        Input parameters:
+            State   -   structure which stores algorithm state between calls and
+                        which is used for reverse communication. Must be initialized
+                        with MinLBFGS.
+
+        If suborutine returned False, iterative proces has converged.
+
+        If subroutine returned True, caller should calculate function value
+        State.F an gradient State.G[0..N-1] at State.X[0..N-1] and call
+        MinLBFGSIteration again.
+
+          -- ALGLIB --
+             Copyright 20.04.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool minlbfgsiteration(ref lbfgsstate state)
+        {
+            bool result = new bool();
+            int n = 0;
+            int m = 0;
+            int maxits = 0;
+            double epsf = 0;
+            double epsg = 0;
+            double epsx = 0;
+            int i = 0;
+            int j = 0;
+            int ic = 0;
+            int mcinfo = 0;
+            double v = 0;
+            double vv = 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.rstate.stage>=0 )
+            {
+                n = state.rstate.ia[0];
+                m = state.rstate.ia[1];
+                maxits = state.rstate.ia[2];
+                i = state.rstate.ia[3];
+                j = state.rstate.ia[4];
+                ic = state.rstate.ia[5];
+                mcinfo = state.rstate.ia[6];
+                epsf = state.rstate.ra[0];
+                epsg = state.rstate.ra[1];
+                epsx = state.rstate.ra[2];
+                v = state.rstate.ra[3];
+                vv = state.rstate.ra[4];
+            }
+            else
+            {
+                n = -983;
+                m = -989;
+                maxits = -834;
+                i = 900;
+                j = -287;
+                ic = 364;
+                mcinfo = 214;
+                epsf = -338;
+                epsg = -686;
+                epsx = 912;
+                v = 585;
+                vv = 497;
+            }
+            if( state.rstate.stage==0 )
+            {
+                goto lbl_0;
+            }
+            if( state.rstate.stage==1 )
+            {
+                goto lbl_1;
+            }
+            
+            //
+            // Routine body
+            //
+            
+            //
+            // Unload frequently used variables from State structure
+            // (just for typing convinience)
+            //
+            n = state.n;
+            m = state.m;
+            epsg = state.epsg;
+            epsf = state.epsf;
+            epsx = state.epsx;
+            maxits = state.maxits;
+            state.repterminationtype = 0;
+            state.repiterationscount = 0;
+            state.repnfev = 0;
+            
+            //
+            // Update info
+            //
+            state.xupdated = false;
+            
+            //
+            // Calculate F/G
+            //
+            state.rstate.stage = 0;
+            goto lbl_rcomm;
+        lbl_0:
+            state.repnfev = 1;
+            
+            //
+            // Preparations
+            //
+            state.fold = state.f;
+            v = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                v += state.g[i_]*state.g[i_];
+            }
+            v = Math.Sqrt(v);
+            if( (double)(v)==(double)(0) )
+            {
+                state.repterminationtype = 4;
+                result = false;
+                return result;
+            }
+            state.stp = 1.0/v;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.d[i_] = -state.g[i_];
+            }
+            
+            //
+            // Main cycle
+            //
+        lbl_2:
+            if( false )
+            {
+                goto lbl_3;
+            }
+            
+            //
+            // Main cycle: prepare to 1-D line search
+            //
+            state.p = state.k%m;
+            state.q = Math.Min(state.k, m-1);
+            
+            //
+            // Store X[k], G[k]
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.s[state.p,i_] = -state.x[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.y[state.p,i_] = -state.g[i_];
+            }
+            
+            //
+            // Minimize F(x+alpha*d)
+            //
+            state.mcstage = 0;
+            if( state.k!=0 )
+            {
+                state.stp = 1.0;
+            }
+            mcsrch(n, ref state.x, ref state.f, ref state.g, ref state.d, ref state.stp, ref mcinfo, ref state.nfev, ref state.work, ref state, ref state.mcstage);
+        lbl_4:
+            if( state.mcstage==0 )
+            {
+                goto lbl_5;
+            }
+            state.rstate.stage = 1;
+            goto lbl_rcomm;
+        lbl_1:
+            mcsrch(n, ref state.x, ref state.f, ref state.g, ref state.d, ref state.stp, ref mcinfo, ref state.nfev, ref state.work, ref state, ref state.mcstage);
+            goto lbl_4;
+        lbl_5:
+            
+            //
+            // Main cycle: update information and Hessian.
+            // Check stopping conditions.
+            //
+            state.repnfev = state.repnfev+state.nfev;
+            state.repiterationscount = state.repiterationscount+1;
+            
+            //
+            // Calculate S[k], Y[k], Rho[k], GammaK
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.s[state.p,i_] = state.s[state.p,i_] + state.x[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.y[state.p,i_] = state.y[state.p,i_] + state.g[i_];
+            }
+            
+            //
+            // Stopping conditions
+            //
+            if( state.repiterationscount>=maxits & maxits>0 )
+            {
+                
+                //
+                // Too many iterations
+                //
+                state.repterminationtype = 5;
+                result = false;
+                return result;
+            }
+            v = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                v += state.g[i_]*state.g[i_];
+            }
+            if( (double)(Math.Sqrt(v))<=(double)(epsg) )
+            {
+                
+                //
+                // Gradient is small enough
+                //
+                state.repterminationtype = 4;
+                result = false;
+                return result;
+            }
+            if( (double)(state.fold-state.f)<=(double)(epsf*Math.Max(Math.Abs(state.fold), Math.Max(Math.Abs(state.f), 1.0))) )
+            {
+                
+                //
+                // F(k+1)-F(k) is small enough
+                //
+                state.repterminationtype = 1;
+                result = false;
+                return result;
+            }
+            v = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                v += state.s[state.p,i_]*state.s[state.p,i_];
+            }
+            if( (double)(Math.Sqrt(v))<=(double)(epsx) )
+            {
+                
+                //
+                // X(k+1)-X(k) is small enough
+                //
+                state.repterminationtype = 2;
+                result = false;
+                return result;
+            }
+            
+            //
+            // Calculate Rho[k], GammaK
+            //
+            v = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                v += state.y[state.p,i_]*state.s[state.p,i_];
+            }
+            vv = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                vv += state.y[state.p,i_]*state.y[state.p,i_];
+            }
+            if( (double)(v)==(double)(0) | (double)(vv)==(double)(0) )
+            {
+                
+                //
+                // Rounding errors make further iterations impossible.
+                //
+                state.repterminationtype = -2;
+                result = false;
+                return result;
+            }
+            state.rho[state.p] = 1/v;
+            state.gammak = v/vv;
+            
+            //
+            //  Calculate d(k+1) = H(k+1)*g(k+1)
+            //
+            //  for I:=K downto K-Q do
+            //      V = s(i)^T * work(iteration:I)
+            //      theta(i) = V
+            //      work(iteration:I+1) = work(iteration:I) - V*Rho(i)*y(i)
+            //  work(last iteration) = H0*work(last iteration)
+            //  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(i_=0; i_<=n-1;i_++)
+            {
+                state.work[i_] = state.g[i_];
+            }
+            for(i=state.k; i>=state.k-state.q; i--)
+            {
+                ic = i%m;
+                v = 0.0;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    v += state.s[ic,i_]*state.work[i_];
+                }
+                state.theta[ic] = v;
+                vv = v*state.rho[ic];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.work[i_] = state.work[i_] - vv*state.y[ic,i_];
+                }
+            }
+            v = state.gammak;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.work[i_] = v*state.work[i_];
+            }
+            for(i=state.k-state.q; i<=state.k; i++)
+            {
+                ic = i%m;
+                v = 0.0;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    v += state.y[ic,i_]*state.work[i_];
+                }
+                vv = state.rho[ic]*(-v+state.theta[ic]);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.work[i_] = state.work[i_] + vv*state.s[ic,i_];
+                }
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.d[i_] = -state.work[i_];
+            }
+            
+            //
+            // Next step
+            //
+            state.fold = state.f;
+            state.k = state.k+1;
+            state.xupdated = true;
+            goto lbl_2;
+        lbl_3:
+            result = false;
+            return result;
+            
+            //
+            // Saving state
+            //
+        lbl_rcomm:
+            result = true;
+            state.rstate.ia[0] = n;
+            state.rstate.ia[1] = m;
+            state.rstate.ia[2] = maxits;
+            state.rstate.ia[3] = i;
+            state.rstate.ia[4] = j;
+            state.rstate.ia[5] = ic;
+            state.rstate.ia[6] = mcinfo;
+            state.rstate.ra[0] = epsf;
+            state.rstate.ra[1] = epsg;
+            state.rstate.ra[2] = epsx;
+            state.rstate.ra[3] = v;
+            state.rstate.ra[4] = vv;
+            return result;
+        }
+
+
+        /*************************************************************************
+        L-BFGS algorithm results
+
+        Called after MinLBFGSIteration returned False.
+
+        Input parameters:
+            State   -   algorithm state (used by MinLBFGSIteration).
+
+        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
+                        * Rep.IterationsCount contains iterations count
+                        * NFEV countains number of function calculations
+
+          -- ALGLIB --
+             Copyright 14.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void minlbfgsresults(ref lbfgsstate state,
+            ref double[] x,
+            ref lbfgsreport rep)
+        {
+            int i_ = 0;
+
+            x = new double[state.n-1+1];
+            for(i_=0; i_<=state.n-1;i_++)
+            {
+                x[i_] = state.x[i_];
+            }
+            rep.iterationscount = state.repiterationscount;
+            rep.nfev = state.repnfev;
+            rep.terminationtype = state.repterminationtype;
+        }
+
+
+        /*************************************************************************
+        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
+        *************************************************************************/
+        private static void mcsrch(int n,
+            ref double[] x,
+            ref double f,
+            ref double[] g,
+            ref double[] s,
+            ref double stp,
+            ref int info,
+            ref int nfev,
+            ref double[] wa,
+            ref lbfgsstate state,
+            ref int stage)
+        {
+            double v = 0;
+            double p5 = 0;
+            double p66 = 0;
+            double zero = 0;
+            int i_ = 0;
+
+            
+            //
+            // init
+            //
+            p5 = 0.5;
+            p66 = 0.66;
+            state.xtrapf = 4.0;
+            zero = 0;
+            
+            //
+            // Main cycle
+            //
+            while( true )
+            {
+                if( stage==0 )
+                {
+                    
+                    //
+                    // NEXT
+                    //
+                    stage = 2;
+                    continue;
+                }
+                if( stage==2 )
+                {
+                    state.infoc = 1;
+                    info = 0;
+                    
+                    //
+                    //     CHECK THE INPUT PARAMETERS FOR ERRORS.
+                    //
+                    if( n<=0 | (double)(stp)<=(double)(0) | (double)(ftol)<(double)(0) | (double)(gtol)<(double)(zero) | (double)(xtol)<(double)(zero) | (double)(stpmin)<(double)(zero) | (double)(stpmax)<(double)(stpmin) | maxfev<=0 )
+                    {
+                        stage = 0;
+                        return;
+                    }
+                    
+                    //
+                    //     COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION
+                    //     AND CHECK THAT S IS A DESCENT DIRECTION.
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        v += g[i_]*s[i_];
+                    }
+                    state.dginit = v;
+                    if( (double)(state.dginit)>=(double)(0) )
+                    {
+                        stage = 0;
+                        return;
+                    }
+                    
+                    //
+                    //     INITIALIZE LOCAL VARIABLES.
+                    //
+                    state.brackt = false;
+                    state.stage1 = true;
+                    nfev = 0;
+                    state.finit = f;
+                    state.dgtest = ftol*state.dginit;
+                    state.width = stpmax-stpmin;
+                    state.width1 = state.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.stx = 0;
+                    state.fx = state.finit;
+                    state.dgx = state.dginit;
+                    state.sty = 0;
+                    state.fy = state.finit;
+                    state.dgy = state.dginit;
+                    
+                    //
+                    // NEXT
+                    //
+                    stage = 3;
+                    continue;
+                }
+                if( stage==3 )
+                {
+                    
+                    //
+                    //     START OF ITERATION.
+                    //
+                    //     SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND
+                    //     TO THE PRESENT INTERVAL OF UNCERTAINTY.
+                    //
+                    if( state.brackt )
+                    {
+                        if( (double)(state.stx)<(double)(state.sty) )
+                        {
+                            state.stmin = state.stx;
+                            state.stmax = state.sty;
+                        }
+                        else
+                        {
+                            state.stmin = state.sty;
+                            state.stmax = state.stx;
+                        }
+                    }
+                    else
+                    {
+                        state.stmin = state.stx;
+                        state.stmax = stp+state.xtrapf*(stp-state.stx);
+                    }
+                    
+                    //
+                    //        FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN.
+                    //
+                    if( (double)(stp)>(double)(stpmax) )
+                    {
+                        stp = stpmax;
+                    }
+                    if( (double)(stp)<(double)(stpmin) )
+                    {
+                        stp = stpmin;
+                    }
+                    
+                    //
+                    //        IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET
+                    //        STP BE THE LOWEST POINT OBTAINED SO FAR.
+                    //
+                    if( state.brackt & ((double)(stp)<=(double)(state.stmin) | (double)(stp)>=(double)(state.stmax)) | nfev>=maxfev-1 | state.infoc==0 | state.brackt & (double)(state.stmax-state.stmin)<=(double)(xtol*state.stmax) )
+                    {
+                        stp = state.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;
+                }
+                if( stage==4 )
+                {
+                    info = 0;
+                    nfev = nfev+1;
+                    v = 0.0;
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        v += g[i_]*s[i_];
+                    }
+                    state.dg = v;
+                    state.ftest1 = state.finit+stp*state.dgtest;
+                    
+                    //
+                    //        TEST FOR CONVERGENCE.
+                    //
+                    if( state.brackt & ((double)(stp)<=(double)(state.stmin) | (double)(stp)>=(double)(state.stmax)) | state.infoc==0 )
+                    {
+                        info = 6;
+                    }
+                    if( (double)(stp)==(double)(stpmax) & (double)(f)<=(double)(state.ftest1) & (double)(state.dg)<=(double)(state.dgtest) )
+                    {
+                        info = 5;
+                    }
+                    if( (double)(stp)==(double)(stpmin) & ((double)(f)>(double)(state.ftest1) | (double)(state.dg)>=(double)(state.dgtest)) )
+                    {
+                        info = 4;
+                    }
+                    if( nfev>=maxfev )
+                    {
+                        info = 3;
+                    }
+                    if( state.brackt & (double)(state.stmax-state.stmin)<=(double)(xtol*state.stmax) )
+                    {
+                        info = 2;
+                    }
+                    if( (double)(f)<=(double)(state.ftest1) & (double)(Math.Abs(state.dg))<=(double)(-(gtol*state.dginit)) )
+                    {
+                        info = 1;
+                    }
+                    
+                    //
+                    //        CHECK FOR TERMINATION.
+                    //
+                    if( info!=0 )
+                    {
+                        stage = 0;
+                        return;
+                    }
+                    
+                    //
+                    //        IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED
+                    //        FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE.
+                    //
+                    if( state.stage1 & (double)(f)<=(double)(state.ftest1) & (double)(state.dg)>=(double)(Math.Min(ftol, gtol)*state.dginit) )
+                    {
+                        state.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.stage1 & (double)(f)<=(double)(state.fx) & (double)(f)>(double)(state.ftest1) )
+                    {
+                        
+                        //
+                        //           DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES.
+                        //
+                        state.fm = f-stp*state.dgtest;
+                        state.fxm = state.fx-state.stx*state.dgtest;
+                        state.fym = state.fy-state.sty*state.dgtest;
+                        state.dgm = state.dg-state.dgtest;
+                        state.dgxm = state.dgx-state.dgtest;
+                        state.dgym = state.dgy-state.dgtest;
+                        
+                        //
+                        //           CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
+                        //           AND TO COMPUTE THE NEW STEP.
+                        //
+                        mcstep(ref state.stx, ref state.fxm, ref state.dgxm, ref state.sty, ref state.fym, ref state.dgym, ref stp, state.fm, state.dgm, ref state.brackt, state.stmin, state.stmax, ref state.infoc);
+                        
+                        //
+                        //           RESET THE FUNCTION AND GRADIENT VALUES FOR F.
+                        //
+                        state.fx = state.fxm+state.stx*state.dgtest;
+                        state.fy = state.fym+state.sty*state.dgtest;
+                        state.dgx = state.dgxm+state.dgtest;
+                        state.dgy = state.dgym+state.dgtest;
+                    }
+                    else
+                    {
+                        
+                        //
+                        //           CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
+                        //           AND TO COMPUTE THE NEW STEP.
+                        //
+                        mcstep(ref state.stx, ref state.fx, ref state.dgx, ref state.sty, ref state.fy, ref state.dgy, ref stp, f, state.dg, ref state.brackt, state.stmin, state.stmax, ref state.infoc);
+                    }
+                    
+                    //
+                    //        FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE
+                    //        INTERVAL OF UNCERTAINTY.
+                    //
+                    if( state.brackt )
+                    {
+                        if( (double)(Math.Abs(state.sty-state.stx))>=(double)(p66*state.width1) )
+                        {
+                            stp = state.stx+p5*(state.sty-state.stx);
+                        }
+                        state.width1 = state.width;
+                        state.width = Math.Abs(state.sty-state.stx);
+                    }
+                    
+                    //
+                    //  NEXT.
+                    //
+                    stage = 3;
+                    continue;
+                }
+            }
+        }
+
+
+        private static void mcstep(ref double stx,
+            ref double fx,
+            ref double dx,
+            ref double sty,
+            ref double fy,
+            ref double dy,
+            ref double stp,
+            double fp,
+            double dp,
+            ref bool brackt,
+            double stmin,
+            double stmax,
+            ref int info)
+        {
+            bool bound = new bool();
+            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;
+
+            info = 0;
+            
+            //
+            //     CHECK THE INPUT PARAMETERS FOR ERRORS.
+            //
+            if( brackt & ((double)(stp)<=(double)(Math.Min(stx, sty)) | (double)(stp)>=(double)(Math.Max(stx, sty))) | (double)(dx*(stp-stx))>=(double)(0) | (double)(stmax)<(double)(stmin) )
+            {
+                return;
+            }
+            
+            //
+            //     DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN.
+            //
+            sgnd = dp*(dx/Math.Abs(dx));
+            
+            //
+            //     FIRST CASE. A HIGHER FUNCTION VALUE.
+            //     THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER
+            //     TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN,
+            //     ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN.
+            //
+            if( (double)(fp)>(double)(fx) )
+            {
+                info = 1;
+                bound = true;
+                theta = 3*(fx-fp)/(stp-stx)+dx+dp;
+                s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dx), Math.Abs(dp)));
+                gamma = s*Math.Sqrt(AP.Math.Sqr(theta/s)-dx/s*(dp/s));
+                if( (double)(stp)<(double)(stx) )
+                {
+                    gamma = -gamma;
+                }
+                p = gamma-dx+theta;
+                q = gamma-dx+gamma+dp;
+                r = p/q;
+                stpc = stx+r*(stp-stx);
+                stpq = stx+dx/((fx-fp)/(stp-stx)+dx)/2*(stp-stx);
+                if( (double)(Math.Abs(stpc-stx))<(double)(Math.Abs(stpq-stx)) )
+                {
+                    stpf = stpc;
+                }
+                else
+                {
+                    stpf = stpc+(stpq-stpc)/2;
+                }
+                brackt = true;
+            }
+            else
+            {
+                if( (double)(sgnd)<(double)(0) )
+                {
+                    
+                    //
+                    //     SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF
+                    //     OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC
+                    //     STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP,
+                    //     THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN.
+                    //
+                    info = 2;
+                    bound = false;
+                    theta = 3*(fx-fp)/(stp-stx)+dx+dp;
+                    s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dx), Math.Abs(dp)));
+                    gamma = s*Math.Sqrt(AP.Math.Sqr(theta/s)-dx/s*(dp/s));
+                    if( (double)(stp)>(double)(stx) )
+                    {
+                        gamma = -gamma;
+                    }
+                    p = gamma-dp+theta;
+                    q = gamma-dp+gamma+dx;
+                    r = p/q;
+                    stpc = stp+r*(stx-stp);
+                    stpq = stp+dp/(dp-dx)*(stx-stp);
+                    if( (double)(Math.Abs(stpc-stp))>(double)(Math.Abs(stpq-stp)) )
+                    {
+                        stpf = stpc;
+                    }
+                    else
+                    {
+                        stpf = stpq;
+                    }
+                    brackt = true;
+                }
+                else
+                {
+                    if( (double)(Math.Abs(dp))<(double)(Math.Abs(dx)) )
+                    {
+                        
+                        //
+                        //     THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
+                        //     SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES.
+                        //     THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY
+                        //     IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC
+                        //     IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE
+                        //     EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO
+                        //     COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP
+                        //     CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN.
+                        //
+                        info = 3;
+                        bound = true;
+                        theta = 3*(fx-fp)/(stp-stx)+dx+dp;
+                        s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dx), Math.Abs(dp)));
+                        
+                        //
+                        //        THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND
+                        //        TO INFINITY IN THE DIRECTION OF THE STEP.
+                        //
+                        gamma = s*Math.Sqrt(Math.Max(0, AP.Math.Sqr(theta/s)-dx/s*(dp/s)));
+                        if( (double)(stp)>(double)(stx) )
+                        {
+                            gamma = -gamma;
+                        }
+                        p = gamma-dp+theta;
+                        q = gamma+(dx-dp)+gamma;
+                        r = p/q;
+                        if( (double)(r)<(double)(0) & (double)(gamma)!=(double)(0) )
+                        {
+                            stpc = stp+r*(stx-stp);
+                        }
+                        else
+                        {
+                            if( (double)(stp)>(double)(stx) )
+                            {
+                                stpc = stmax;
+                            }
+                            else
+                            {
+                                stpc = stmin;
+                            }
+                        }
+                        stpq = stp+dp/(dp-dx)*(stx-stp);
+                        if( brackt )
+                        {
+                            if( (double)(Math.Abs(stp-stpc))<(double)(Math.Abs(stp-stpq)) )
+                            {
+                                stpf = stpc;
+                            }
+                            else
+                            {
+                                stpf = stpq;
+                            }
+                        }
+                        else
+                        {
+                            if( (double)(Math.Abs(stp-stpc))>(double)(Math.Abs(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;
+                        if( brackt )
+                        {
+                            theta = 3*(fp-fy)/(sty-stp)+dy+dp;
+                            s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dy), Math.Abs(dp)));
+                            gamma = s*Math.Sqrt(AP.Math.Sqr(theta/s)-dy/s*(dp/s));
+                            if( (double)(stp)>(double)(sty) )
+                            {
+                                gamma = -gamma;
+                            }
+                            p = gamma-dp+theta;
+                            q = gamma-dp+gamma+dy;
+                            r = p/q;
+                            stpc = stp+r*(sty-stp);
+                            stpf = stpc;
+                        }
+                        else
+                        {
+                            if( (double)(stp)>(double)(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( (double)(fp)>(double)(fx) )
+            {
+                sty = stp;
+                fy = fp;
+                dy = dp;
+            }
+            else
+            {
+                if( (double)(sgnd)<(double)(0.0) )
+                {
+                    sty = stx;
+                    fy = fx;
+                    dy = dx;
+                }
+                stx = stp;
+                fx = fp;
+                dx = dp;
+            }
+            
+            //
+            //     COMPUTE THE NEW STEP AND SAFEGUARD IT.
+            //
+            stpf = Math.Min(stmax, stpf);
+            stpf = Math.Max(stmin, stpf);
+            stp = stpf;
+            if( brackt & bound )
+            {
+                if( (double)(sty)>(double)(stx) )
+                {
+                    stp = Math.Min(stx+0.66*(sty-stx), stp);
+                }
+                else
+                {
+                    stp = Math.Max(stx+0.66*(sty-stx), stp);
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lda.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lda.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lda.cs	(revision 2645)
@@ -0,0 +1,476 @@
+/*************************************************************************
+Copyright (c) 2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class lda
+    {
+        /*************************************************************************
+        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]
+
+          -- ALGLIB --
+             Copyright 31.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fisherlda(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            ref int info,
+            ref double[] w)
+        {
+            double[,] w2 = new double[0,0];
+            int i_ = 0;
+
+            fisherldan(ref xy, npoints, nvars, nclasses, ref info, ref w2);
+            if( info>0 )
+            {
+                w = new double[nvars-1+1];
+                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)
+
+          -- ALGLIB --
+             Copyright 31.05.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void fisherldan(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            ref int info,
+            ref double[,] w)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int m = 0;
+            double v = 0;
+            int[] c = new int[0];
+            double[] mu = new double[0];
+            double[,] muc = new double[0,0];
+            int[] nc = new int[0];
+            double[,] sw = new double[0,0];
+            double[,] st = new double[0,0];
+            double[,] z = new double[0,0];
+            double[,] z2 = new double[0,0];
+            double[,] tm = new double[0,0];
+            double[,] sbroot = new double[0,0];
+            double[,] a = new double[0,0];
+            double[,] xyproj = new double[0,0];
+            double[,] wproj = new double[0,0];
+            double[] tf = new double[0];
+            double[] d = new double[0];
+            double[] d2 = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+
+            
+            //
+            // Test data
+            //
+            if( npoints<0 | nvars<1 | nclasses<2 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( (int)Math.Round(xy[i,nvars])<0 | (int)Math.Round(xy[i,nvars])>=nclasses )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Special case: NPoints<=1
+            // Degenerate task.
+            //
+            if( npoints<=1 )
+            {
+                info = 2;
+                w = new double[nvars-1+1, nvars-1+1];
+                for(i=0; i<=nvars-1; i++)
+                {
+                    for(j=0; j<=nvars-1; j++)
+                    {
+                        if( i==j )
+                        {
+                            w[i,j] = 1;
+                        }
+                        else
+                        {
+                            w[i,j] = 0;
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // Prepare temporaries
+            //
+            tf = new double[nvars-1+1];
+            work = new double[Math.Max(nvars, npoints)+1];
+            
+            //
+            // Convert class labels from reals to integers (just for convenience)
+            //
+            c = new int[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                c[i] = (int)Math.Round(xy[i,nvars]);
+            }
+            
+            //
+            // Calculate class sizes and means
+            //
+            mu = new double[nvars-1+1];
+            muc = new double[nclasses-1+1, nvars-1+1];
+            nc = new int[nclasses-1+1];
+            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,j] = 0;
+                }
+            }
+            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],i_] = muc[c[i],i_] + xy[i,i_];
+                }
+                nc[c[i]] = nc[c[i]]+1;
+            }
+            for(i=0; i<=nclasses-1; i++)
+            {
+                v = (double)(1)/(double)(nc[i]);
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    muc[i,i_] = v*muc[i,i_];
+                }
+            }
+            v = (double)(1)/(double)(npoints);
+            for(i_=0; i_<=nvars-1;i_++)
+            {
+                mu[i_] = v*mu[i_];
+            }
+            
+            //
+            // Create ST matrix
+            //
+            st = new double[nvars-1+1, nvars-1+1];
+            for(i=0; i<=nvars-1; i++)
+            {
+                for(j=0; j<=nvars-1; j++)
+                {
+                    st[i,j] = 0;
+                }
+            }
+            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,i_] = st[i,i_] + v*tf[i_];
+                    }
+                }
+            }
+            
+            //
+            // Create SW matrix
+            //
+            sw = new double[nvars-1+1, nvars-1+1];
+            for(i=0; i<=nvars-1; i++)
+            {
+                for(j=0; j<=nvars-1; j++)
+                {
+                    sw[i,j] = 0;
+                }
+            }
+            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,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( !sevd.smatrixevd(st, nvars, 1, true, ref d, ref z) )
+            {
+                info = -4;
+                return;
+            }
+            w = new double[nvars-1+1, nvars-1+1];
+            if( (double)(d[nvars-1])<=(double)(0) | (double)(d[0])<=(double)(1000*AP.Math.MachineEpsilon*d[nvars-1]) )
+            {
+                
+                //
+                // Special case: D[NVars-1]<=0
+                // Degenerate task (all variables takes the same value).
+                //
+                if( (double)(d[nvars-1])<=(double)(0) )
+                {
+                    info = 2;
+                    for(i=0; i<=nvars-1; i++)
+                    {
+                        for(j=0; j<=nvars-1; j++)
+                        {
+                            if( i==j )
+                            {
+                                w[i,j] = 1;
+                            }
+                            else
+                            {
+                                w[i,j] = 0;
+                            }
+                        }
+                    }
+                    return;
+                }
+                
+                //
+                // Special case: degenerate ST matrix, multicollinearity found.
+                // Since we know ST eigenvalues/vectors we can translate task to
+                // non-degenerate form.
+                //
+                // Let WG is orthogonal basis of the non zero variance subspace
+                // of the ST and let WZ is orthogonal basis of the zero variance
+                // subspace.
+                //
+                // Projection on WG allows us to use LDA on reduced M-dimensional
+                // subspace, N-M vectors of WZ allows us to update reduced LDA
+                // factors to full N-dimensional subspace.
+                //
+                m = 0;
+                for(k=0; k<=nvars-1; k++)
+                {
+                    if( (double)(d[k])<=(double)(1000*AP.Math.MachineEpsilon*d[nvars-1]) )
+                    {
+                        m = k+1;
+                    }
+                }
+                System.Diagnostics.Debug.Assert(m!=0, "FisherLDAN: internal error #1");
+                xyproj = new double[npoints-1+1, nvars-m+1];
+                blas.matrixmatrixmultiply(ref xy, 0, npoints-1, 0, nvars-1, false, ref z, 0, nvars-1, m, nvars-1, false, 1.0, ref xyproj, 0, npoints-1, 0, nvars-m-1, 0.0, ref work);
+                for(i=0; i<=npoints-1; i++)
+                {
+                    xyproj[i,nvars-m] = xy[i,nvars];
+                }
+                fisherldan(ref xyproj, npoints, nvars-m, nclasses, ref info, ref wproj);
+                if( info<0 )
+                {
+                    return;
+                }
+                blas.matrixmatrixmultiply(ref z, 0, nvars-1, m, nvars-1, false, ref wproj, 0, nvars-m-1, 0, nvars-m-1, false, 1.0, ref w, 0, nvars-1, 0, nvars-m-1, 0.0, ref work);
+                for(k=nvars-m; k<=nvars-1; k++)
+                {
+                    for(i_=0; i_<=nvars-1;i_++)
+                    {
+                        w[i_,k] = z[i_,k-(nvars-m)];
+                    }
+                }
+                info = 2;
+            }
+            else
+            {
+                
+                //
+                // General case: no multicollinearity
+                //
+                tm = new double[nvars-1+1, nvars-1+1];
+                a = new double[nvars-1+1, nvars-1+1];
+                blas.matrixmatrixmultiply(ref sw, 0, nvars-1, 0, nvars-1, false, ref z, 0, nvars-1, 0, nvars-1, false, 1.0, ref tm, 0, nvars-1, 0, nvars-1, 0.0, ref work);
+                blas.matrixmatrixmultiply(ref z, 0, nvars-1, 0, nvars-1, true, ref tm, 0, nvars-1, 0, nvars-1, false, 1.0, ref a, 0, nvars-1, 0, nvars-1, 0.0, ref work);
+                for(i=0; i<=nvars-1; i++)
+                {
+                    for(j=0; j<=nvars-1; j++)
+                    {
+                        a[i,j] = a[i,j]/Math.Sqrt(d[i]*d[j]);
+                    }
+                }
+                if( !sevd.smatrixevd(a, nvars, 1, true, ref d2, ref z2) )
+                {
+                    info = -4;
+                    return;
+                }
+                for(k=0; k<=nvars-1; k++)
+                {
+                    for(i=0; i<=nvars-1; i++)
+                    {
+                        tf[i] = z2[i,k]/Math.Sqrt(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,k] = v;
+                    }
+                }
+            }
+            
+            //
+            // Post-processing:
+            // * normalization
+            // * converting to non-negative form, if possible
+            //
+            for(k=0; k<=nvars-1; k++)
+            {
+                v = 0.0;
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    v += w[i_,k]*w[i_,k];
+                }
+                v = 1/Math.Sqrt(v);
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    w[i_,k] = v*w[i_,k];
+                }
+                v = 0;
+                for(i=0; i<=nvars-1; i++)
+                {
+                    v = v+w[i,k];
+                }
+                if( (double)(v)<(double)(0) )
+                {
+                    for(i_=0; i_<=nvars-1;i_++)
+                    {
+                        w[i_,k] = -1*w[i_,k];
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ldlt.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ldlt.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ldlt.cs	(revision 2645)
@@ -0,0 +1,1239 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ldlt
+    {
+        /*************************************************************************
+        LDLTDecomposition of a symmetric matrix
+
+        The algorithm represents a symmetric matrix (which is not necessarily
+        positive definite) as A=L*D*L' or A = U*D*U', where D is a block-diagonal
+        matrix with blocks 1x1 or 2x2, matrix L (matrix U) is a product of lower
+        (upper) triangular matrices with unit diagonal and permutation matrices.
+
+        Input parameters:
+            A       -   factorized matrix, array with elements [0..N-1, 0..N-1].
+                        If IsUpper  True, then the upper triangle contains
+                        elements of symmetric matrix A, and the lower triangle is
+                        not used.
+                        The same applies if IsUpper = False.
+            N       -   size of factorized matrix.
+            IsUpper -   parameter which shows a method of matrix definition (lower
+                        or upper triangle).
+
+        Output parameters:
+            A       -   matrices D and U, if IsUpper = True, or L, if IsUpper = False,
+                        in compact form, replacing the upper (lower) triangle of
+                        matrix A. In that case, the elements under (over) the main
+                        diagonal are not used nor modified.
+            Pivots  -   tables of performed permutations (see below).
+
+        If IsUpper = True, then A = U*D*U', U = P(n)*U(n)*...*P(k)*U(k), where
+        P(k) is the permutation matrix, U(k) - upper triangular matrix with its
+        unit main diagonal and k decreases from n with step s which is equal to
+        1 or 2 (according to the size of the blocks of matrix D).
+
+                (   I    v    0   )   k-s+1
+        U(k) =  (   0    I    0   )   s
+                (   0    0    I   )   n-k-1
+                   k-s+1 s   n-k-1
+
+        If Pivots[k]>=0, then s=1, P(k) - permutation of rows k and Pivots[k], the
+        vectorv forming matrix U(k) is stored in elements A(0:k-1,k), D(k) replaces
+        A(k,k). If Pivots[k]=Pivots[k-1]<0 then s=2, P(k) - permutation of rows k-1
+        and N+Pivots[k-1], the vector v forming matrix U(k) is stored in elements
+        A(0:k-1,k:k+1), the upper triangle of block D(k) is stored in A(k,k),
+        A(k,k+1) and A(k+1,k+1).
+
+        If IsUpper = False, then A = L*D*L', L=P(0)*L(0)*...*P(k)*L(k), where P(k)
+        is the permutation matrix, L(k)  lower triangular matrix with unit main
+        diagonal and k decreases from 1 with step s which is equal to 1 or 2
+        (according to the size of the blocks of matrix D).
+
+                (   I    0     0   )  k-1
+        L(k) =  (   0    I     0   )  s
+                (   0    v     I   )  n-k-s+1
+                   k-1   s  n-k-s+1
+
+        If Pivots[k]>=0 then s=1, P(k)  permutation of rows k and Pivots[k], the
+        vector v forming matrix L(k) is stored in elements A(k+1:n-1,k), D(k)
+        replaces A(k,k). If Pivots[k]=Pivots[k+1]<0 then s=2, P(k) - permutation
+        of rows k+1 and N+Pivots[k+1], the vector v forming matrix L(k) is stored
+        in elements A(k+2:n-1,k:k+1), the lower triangle of block D(k) is stored in
+        A(k,k), A(k+1,k) and A(k+1,k+1).
+
+          -- 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
+        *************************************************************************/
+        public static void smatrixldlt(ref double[,] a,
+            int n,
+            bool isupper,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int imax = 0;
+            int j = 0;
+            int jmax = 0;
+            int k = 0;
+            int kk = 0;
+            int kp = 0;
+            int kstep = 0;
+            double absakk = 0;
+            double alpha = 0;
+            double colmax = 0;
+            double d11 = 0;
+            double d12 = 0;
+            double d21 = 0;
+            double d22 = 0;
+            double r1 = 0;
+            double rowmax = 0;
+            double t = 0;
+            double wk = 0;
+            double wkm1 = 0;
+            double wkp1 = 0;
+            int ii = 0;
+            int i1 = 0;
+            int i2 = 0;
+            double vv = 0;
+            double[] temp = new double[0];
+            int i_ = 0;
+
+            pivots = new int[n-1+1];
+            temp = new double[n-1+1];
+            
+            //
+            // Initialize ALPHA for use in choosing pivot block size.
+            //
+            alpha = (1+Math.Sqrt(17))/8;
+            if( isupper )
+            {
+                
+                //
+                // Factorize A as U*D*U' using the upper triangle of A
+                //
+                //
+                // K is the main loop index, decreasing from N to 1 in steps of
+                // 1 or 2
+                //
+                k = n-1;
+                while( k>=0 )
+                {
+                    kstep = 1;
+                    
+                    //
+                    // Determine rows and columns to be interchanged and whether
+                    // a 1-by-1 or 2-by-2 pivot block will be used
+                    //
+                    absakk = Math.Abs(a[k,k]);
+                    
+                    //
+                    // IMAX is the row-index of the largest off-diagonal element in
+                    // column K+1, and COLMAX is its absolute value
+                    //
+                    if( k>0 )
+                    {
+                        imax = 1;
+                        for(ii=2; ii<=k; ii++)
+                        {
+                            if( (double)(Math.Abs(a[ii-1,k]))>(double)(Math.Abs(a[imax-1,k])) )
+                            {
+                                imax = ii;
+                            }
+                        }
+                        colmax = Math.Abs(a[imax-1,k]);
+                    }
+                    else
+                    {
+                        colmax = 0;
+                    }
+                    if( (double)(Math.Max(absakk, colmax))==(double)(0) )
+                    {
+                        
+                        //
+                        // Column K is zero
+                        //
+                        kp = k;
+                    }
+                    else
+                    {
+                        if( (double)(absakk)>=(double)(alpha*colmax) )
+                        {
+                            
+                            //
+                            // no interchange, use 1-by-1 pivot block
+                            //
+                            kp = k;
+                        }
+                        else
+                        {
+                            
+                            //
+                            // JMAX is the column-index of the largest off-diagonal
+                            // element in row IMAX, and ROWMAX is its absolute value
+                            //
+                            jmax = imax+1;
+                            for(ii=imax+2; ii<=k+1; ii++)
+                            {
+                                if( (double)(Math.Abs(a[imax-1,ii-1]))>(double)(Math.Abs(a[imax-1,jmax-1])) )
+                                {
+                                    jmax = ii;
+                                }
+                            }
+                            rowmax = Math.Abs(a[imax-1,jmax-1]);
+                            if( imax>1 )
+                            {
+                                jmax = 1;
+                                for(ii=2; ii<=imax-1; ii++)
+                                {
+                                    if( (double)(Math.Abs(a[ii-1,imax-1]))>(double)(Math.Abs(a[jmax-1,imax-1])) )
+                                    {
+                                        jmax = ii;
+                                    }
+                                }
+                                rowmax = Math.Max(rowmax, Math.Abs(a[jmax-1,imax-1]));
+                            }
+                            vv = colmax/rowmax;
+                            if( (double)(absakk)>=(double)(alpha*colmax*vv) )
+                            {
+                                
+                                //
+                                // no interchange, use 1-by-1 pivot block
+                                //
+                                kp = k;
+                            }
+                            else
+                            {
+                                if( (double)(Math.Abs(a[imax-1,imax-1]))>=(double)(alpha*rowmax) )
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K and IMAX, use 1-by-1
+                                    // pivot block
+                                    //
+                                    kp = imax-1;
+                                }
+                                else
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K-1 and IMAX, use 2-by-2
+                                    // pivot block
+                                    //
+                                    kp = imax-1;
+                                    kstep = 2;
+                                }
+                            }
+                        }
+                        kk = k+1-kstep;
+                        if( kp+1!=kk+1 )
+                        {
+                            
+                            //
+                            // Interchange rows and columns KK and KP+1 in the leading
+                            // submatrix A(0:K,0:K)
+                            //
+                            for(i_=0; i_<=kp-1;i_++)
+                            {
+                                temp[i_] = a[i_,kk];
+                            }
+                            for(i_=0; i_<=kp-1;i_++)
+                            {
+                                a[i_,kk] = a[i_,kp];
+                            }
+                            for(i_=0; i_<=kp-1;i_++)
+                            {
+                                a[i_,kp] = temp[i_];
+                            }
+                            for(i_=kp+1; i_<=kk-1;i_++)
+                            {
+                                temp[i_] = a[i_,kk];
+                            }
+                            for(i_=kp+1; i_<=kk-1;i_++)
+                            {
+                                a[i_,kk] = a[kp,i_];
+                            }
+                            for(i_=kp+1; i_<=kk-1;i_++)
+                            {
+                                a[kp,i_] = temp[i_];
+                            }
+                            t = a[kk,kk];
+                            a[kk,kk] = a[kp,kp];
+                            a[kp,kp] = t;
+                            if( kstep==2 )
+                            {
+                                t = a[k-1,k];
+                                a[k-1,k] = a[kp,k];
+                                a[kp,k] = t;
+                            }
+                        }
+                        
+                        //
+                        // Update the leading submatrix
+                        //
+                        if( kstep==1 )
+                        {
+                            
+                            //
+                            // 1-by-1 pivot block D(k): column k now holds
+                            //
+                            // W(k) = U(k)*D(k)
+                            //
+                            // where U(k) is the k-th column of U
+                            //
+                            // Perform a rank-1 update of A(1:k-1,1:k-1) as
+                            //
+                            // A := A - U(k)*D(k)*U(k)' = A - W(k)*1/D(k)*W(k)'
+                            //
+                            r1 = 1/a[k,k];
+                            for(i=0; i<=k-1; i++)
+                            {
+                                vv = -(r1*a[i,k]);
+                                for(i_=i; i_<=k-1;i_++)
+                                {
+                                    a[i,i_] = a[i,i_] + vv*a[i_,k];
+                                }
+                            }
+                            
+                            //
+                            // Store U(K+1) in column K+1
+                            //
+                            for(i_=0; i_<=k-1;i_++)
+                            {
+                                a[i_,k] = r1*a[i_,k];
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // 2-by-2 pivot block D(k): columns k and k-1 now hold
+                            //
+                            // ( W(k-1) W(k) ) = ( U(k-1) U(k) )*D(k)
+                            //
+                            // where U(k) and U(k-1) are the k-th and (k-1)-th columns
+                            // of U
+                            //
+                            // Perform a rank-2 update of A(1:k-2,1:k-2) as
+                            //
+                            // A := A - ( U(k-1) U(k) )*D(k)*( U(k-1) U(k) )'
+                            //    = A - ( W(k-1) W(k) )*inv(D(k))*( W(k-1) W(k) )'
+                            //
+                            if( k>1 )
+                            {
+                                d12 = a[k-1,k];
+                                d22 = a[k-1,k-1]/d12;
+                                d11 = a[k,k]/d12;
+                                t = 1/(d11*d22-1);
+                                d12 = t/d12;
+                                for(j=k-2; j>=0; j--)
+                                {
+                                    wkm1 = d12*(d11*a[j,k-1]-a[j,k]);
+                                    wk = d12*(d22*a[j,k]-a[j,k-1]);
+                                    for(i_=0; i_<=j;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wk*a[i_,k];
+                                    }
+                                    for(i_=0; i_<=j;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wkm1*a[i_,k-1];
+                                    }
+                                    a[j,k] = wk;
+                                    a[j,k-1] = wkm1;
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Store details of the interchanges in IPIV
+                    //
+                    if( kstep==1 )
+                    {
+                        pivots[k] = kp;
+                    }
+                    else
+                    {
+                        pivots[k] = kp-n;
+                        pivots[k-1] = kp-n;
+                    }
+                    
+                    //
+                    // Decrease K+1 and return to the start of the main loop
+                    //
+                    k = k-kstep;
+                }
+            }
+            else
+            {
+                
+                //
+                // Factorize A as L*D*L' using the lower triangle of A
+                //
+                // K+1 is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2
+                //
+                k = 0;
+                while( k<=n-1 )
+                {
+                    kstep = 1;
+                    
+                    //
+                    // Determine rows and columns to be interchanged and whether
+                    // a 1-by-1 or 2-by-2 pivot block will be used
+                    //
+                    absakk = Math.Abs(a[k,k]);
+                    
+                    //
+                    // IMAX is the row-index of the largest off-diagonal element in
+                    // column K+1, and COLMAX is its absolute value
+                    //
+                    if( k<n-1 )
+                    {
+                        imax = k+1+1;
+                        for(ii=k+1+2; ii<=n; ii++)
+                        {
+                            if( (double)(Math.Abs(a[ii-1,k]))>(double)(Math.Abs(a[imax-1,k])) )
+                            {
+                                imax = ii;
+                            }
+                        }
+                        colmax = Math.Abs(a[imax-1,k]);
+                    }
+                    else
+                    {
+                        colmax = 0;
+                    }
+                    if( (double)(Math.Max(absakk, colmax))==(double)(0) )
+                    {
+                        
+                        //
+                        // Column K+1 is zero
+                        //
+                        kp = k;
+                    }
+                    else
+                    {
+                        if( (double)(absakk)>=(double)(alpha*colmax) )
+                        {
+                            
+                            //
+                            // no interchange, use 1-by-1 pivot block
+                            //
+                            kp = k;
+                        }
+                        else
+                        {
+                            
+                            //
+                            // JMAX is the column-index of the largest off-diagonal
+                            // element in row IMAX, and ROWMAX is its absolute value
+                            //
+                            jmax = k+1;
+                            for(ii=k+1+1; ii<=imax-1; ii++)
+                            {
+                                if( (double)(Math.Abs(a[imax-1,ii-1]))>(double)(Math.Abs(a[imax-1,jmax-1])) )
+                                {
+                                    jmax = ii;
+                                }
+                            }
+                            rowmax = Math.Abs(a[imax-1,jmax-1]);
+                            if( imax<n )
+                            {
+                                jmax = imax+1;
+                                for(ii=imax+2; ii<=n; ii++)
+                                {
+                                    if( (double)(Math.Abs(a[ii-1,imax-1]))>(double)(Math.Abs(a[jmax-1,imax-1])) )
+                                    {
+                                        jmax = ii;
+                                    }
+                                }
+                                rowmax = Math.Max(rowmax, Math.Abs(a[jmax-1,imax-1]));
+                            }
+                            vv = colmax/rowmax;
+                            if( (double)(absakk)>=(double)(alpha*colmax*vv) )
+                            {
+                                
+                                //
+                                // no interchange, use 1-by-1 pivot block
+                                //
+                                kp = k;
+                            }
+                            else
+                            {
+                                if( (double)(Math.Abs(a[imax-1,imax-1]))>=(double)(alpha*rowmax) )
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K+1 and IMAX, use 1-by-1
+                                    // pivot block
+                                    //
+                                    kp = imax-1;
+                                }
+                                else
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K+1+1 and IMAX, use 2-by-2
+                                    // pivot block
+                                    //
+                                    kp = imax-1;
+                                    kstep = 2;
+                                }
+                            }
+                        }
+                        kk = k+kstep-1;
+                        if( kp!=kk )
+                        {
+                            
+                            //
+                            //              Interchange rows and columns KK+1 and KP+1 in the trailing
+                            //              submatrix A(K+1:n,K+1:n)
+                            //
+                            if( kp+1<n )
+                            {
+                                for(i_=kp+1; i_<=n-1;i_++)
+                                {
+                                    temp[i_] = a[i_,kk];
+                                }
+                                for(i_=kp+1; i_<=n-1;i_++)
+                                {
+                                    a[i_,kk] = a[i_,kp];
+                                }
+                                for(i_=kp+1; i_<=n-1;i_++)
+                                {
+                                    a[i_,kp] = temp[i_];
+                                }
+                            }
+                            for(i_=kk+1; i_<=kp-1;i_++)
+                            {
+                                temp[i_] = a[i_,kk];
+                            }
+                            for(i_=kk+1; i_<=kp-1;i_++)
+                            {
+                                a[i_,kk] = a[kp,i_];
+                            }
+                            for(i_=kk+1; i_<=kp-1;i_++)
+                            {
+                                a[kp,i_] = temp[i_];
+                            }
+                            t = a[kk,kk];
+                            a[kk,kk] = a[kp,kp];
+                            a[kp,kp] = t;
+                            if( kstep==2 )
+                            {
+                                t = a[k+1,k];
+                                a[k+1,k] = a[kp,k];
+                                a[kp,k] = t;
+                            }
+                        }
+                        
+                        //
+                        // Update the trailing submatrix
+                        //
+                        if( kstep==1 )
+                        {
+                            
+                            //
+                            // 1-by-1 pivot block D(K+1): column K+1 now holds
+                            //
+                            // W(K+1) = L(K+1)*D(K+1)
+                            //
+                            // where L(K+1) is the K+1-th column of L
+                            //
+                            if( k+1<n )
+                            {
+                                
+                                //
+                                // Perform a rank-1 update of A(K+1+1:n,K+1+1:n) as
+                                //
+                                // A := A - L(K+1)*D(K+1)*L(K+1)' = A - W(K+1)*(1/D(K+1))*W(K+1)'
+                                //
+                                d11 = 1/a[k+1-1,k+1-1];
+                                for(ii=k+1; ii<=n-1; ii++)
+                                {
+                                    vv = -(d11*a[ii,k]);
+                                    for(i_=k+1; i_<=ii;i_++)
+                                    {
+                                        a[ii,i_] = a[ii,i_] + vv*a[i_,k];
+                                    }
+                                }
+                                
+                                //
+                                // Store L(K+1) in column K+1
+                                //
+                                for(i_=k+1; i_<=n-1;i_++)
+                                {
+                                    a[i_,k] = d11*a[i_,k];
+                                }
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // 2-by-2 pivot block D(K+1)
+                            //
+                            if( k<n-2 )
+                            {
+                                
+                                //
+                                // Perform a rank-2 update of A(K+1+2:n,K+1+2:n) as
+                                //
+                                // A := A - ( (A(K+1) A(K+1+1))*D(K+1)**(-1) ) * (A(K+1) A(K+1+1))'
+                                //
+                                // where L(K+1) and L(K+1+1) are the K+1-th and (K+1+1)-th
+                                // columns of L
+                                //
+                                d21 = a[k+1,k];
+                                d11 = a[k+1,k+1]/d21;
+                                d22 = a[k,k]/d21;
+                                t = 1/(d11*d22-1);
+                                d21 = t/d21;
+                                for(j=k+2; j<=n-1; j++)
+                                {
+                                    wk = d21*(d11*a[j,k]-a[j,k+1]);
+                                    wkp1 = d21*(d22*a[j,k+1]-a[j,k]);
+                                    for(i_=j; i_<=n-1;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wk*a[i_,k];
+                                    }
+                                    for(i_=j; i_<=n-1;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wkp1*a[i_,k+1];
+                                    }
+                                    a[j,k] = wk;
+                                    a[j,k+1] = wkp1;
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Store details of the interchanges in IPIV
+                    //
+                    if( kstep==1 )
+                    {
+                        pivots[k+1-1] = kp+1-1;
+                    }
+                    else
+                    {
+                        pivots[k+1-1] = kp+1-1-n;
+                        pivots[k+1+1-1] = kp+1-1-n;
+                    }
+                    
+                    //
+                    // Increase K+1 and return to the start of the main loop
+                    //
+                    k = k+kstep;
+                }
+            }
+        }
+
+
+        public static void ldltdecomposition(ref double[,] a,
+            int n,
+            bool isupper,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int imax = 0;
+            int j = 0;
+            int jmax = 0;
+            int k = 0;
+            int kk = 0;
+            int kp = 0;
+            int kstep = 0;
+            double absakk = 0;
+            double alpha = 0;
+            double colmax = 0;
+            double d11 = 0;
+            double d12 = 0;
+            double d21 = 0;
+            double d22 = 0;
+            double r1 = 0;
+            double rowmax = 0;
+            double t = 0;
+            double wk = 0;
+            double wkm1 = 0;
+            double wkp1 = 0;
+            int ii = 0;
+            int i1 = 0;
+            int i2 = 0;
+            double vv = 0;
+            double[] temp = new double[0];
+            int i_ = 0;
+
+            pivots = new int[n+1];
+            temp = new double[n+1];
+            
+            //
+            // Initialize ALPHA for use in choosing pivot block size.
+            //
+            alpha = (1+Math.Sqrt(17))/8;
+            if( isupper )
+            {
+                
+                //
+                // Factorize A as U*D*U' using the upper triangle of A
+                //
+                //
+                // K is the main loop index, decreasing from N to 1 in steps of
+                // 1 or 2
+                //
+                k = n;
+                while( k>=1 )
+                {
+                    kstep = 1;
+                    
+                    //
+                    // Determine rows and columns to be interchanged and whether
+                    // a 1-by-1 or 2-by-2 pivot block will be used
+                    //
+                    absakk = Math.Abs(a[k,k]);
+                    
+                    //
+                    // IMAX is the row-index of the largest off-diagonal element in
+                    // column K, and COLMAX is its absolute value
+                    //
+                    if( k>1 )
+                    {
+                        imax = 1;
+                        for(ii=2; ii<=k-1; ii++)
+                        {
+                            if( (double)(Math.Abs(a[ii,k]))>(double)(Math.Abs(a[imax,k])) )
+                            {
+                                imax = ii;
+                            }
+                        }
+                        colmax = Math.Abs(a[imax,k]);
+                    }
+                    else
+                    {
+                        colmax = 0;
+                    }
+                    if( (double)(Math.Max(absakk, colmax))==(double)(0) )
+                    {
+                        
+                        //
+                        // Column K is zero
+                        //
+                        kp = k;
+                    }
+                    else
+                    {
+                        if( (double)(absakk)>=(double)(alpha*colmax) )
+                        {
+                            
+                            //
+                            // no interchange, use 1-by-1 pivot block
+                            //
+                            kp = k;
+                        }
+                        else
+                        {
+                            
+                            //
+                            // JMAX is the column-index of the largest off-diagonal
+                            // element in row IMAX, and ROWMAX is its absolute value
+                            //
+                            jmax = imax+1;
+                            for(ii=imax+2; ii<=k; ii++)
+                            {
+                                if( (double)(Math.Abs(a[imax,ii]))>(double)(Math.Abs(a[imax,jmax])) )
+                                {
+                                    jmax = ii;
+                                }
+                            }
+                            rowmax = Math.Abs(a[imax,jmax]);
+                            if( imax>1 )
+                            {
+                                jmax = 1;
+                                for(ii=2; ii<=imax-1; ii++)
+                                {
+                                    if( (double)(Math.Abs(a[ii,imax]))>(double)(Math.Abs(a[jmax,imax])) )
+                                    {
+                                        jmax = ii;
+                                    }
+                                }
+                                rowmax = Math.Max(rowmax, Math.Abs(a[jmax,imax]));
+                            }
+                            vv = colmax/rowmax;
+                            if( (double)(absakk)>=(double)(alpha*colmax*vv) )
+                            {
+                                
+                                //
+                                // no interchange, use 1-by-1 pivot block
+                                //
+                                kp = k;
+                            }
+                            else
+                            {
+                                if( (double)(Math.Abs(a[imax,imax]))>=(double)(alpha*rowmax) )
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K and IMAX, use 1-by-1
+                                    // pivot block
+                                    //
+                                    kp = imax;
+                                }
+                                else
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K-1 and IMAX, use 2-by-2
+                                    // pivot block
+                                    //
+                                    kp = imax;
+                                    kstep = 2;
+                                }
+                            }
+                        }
+                        kk = k-kstep+1;
+                        if( kp!=kk )
+                        {
+                            
+                            //
+                            // Interchange rows and columns KK and KP in the leading
+                            // submatrix A(1:k,1:k)
+                            //
+                            i1 = kp-1;
+                            for(i_=1; i_<=i1;i_++)
+                            {
+                                temp[i_] = a[i_,kk];
+                            }
+                            for(i_=1; i_<=i1;i_++)
+                            {
+                                a[i_,kk] = a[i_,kp];
+                            }
+                            for(i_=1; i_<=i1;i_++)
+                            {
+                                a[i_,kp] = temp[i_];
+                            }
+                            i1 = kp+1;
+                            i2 = kk-1;
+                            for(i_=i1; i_<=i2;i_++)
+                            {
+                                temp[i_] = a[i_,kk];
+                            }
+                            for(i_=i1; i_<=i2;i_++)
+                            {
+                                a[i_,kk] = a[kp,i_];
+                            }
+                            for(i_=i1; i_<=i2;i_++)
+                            {
+                                a[kp,i_] = temp[i_];
+                            }
+                            t = a[kk,kk];
+                            a[kk,kk] = a[kp,kp];
+                            a[kp,kp] = t;
+                            if( kstep==2 )
+                            {
+                                t = a[k-1,k];
+                                a[k-1,k] = a[kp,k];
+                                a[kp,k] = t;
+                            }
+                        }
+                        
+                        //
+                        // Update the leading submatrix
+                        //
+                        if( kstep==1 )
+                        {
+                            
+                            //
+                            // 1-by-1 pivot block D(k): column k now holds
+                            //
+                            // W(k) = U(k)*D(k)
+                            //
+                            // where U(k) is the k-th column of U
+                            //
+                            // Perform a rank-1 update of A(1:k-1,1:k-1) as
+                            //
+                            // A := A - U(k)*D(k)*U(k)' = A - W(k)*1/D(k)*W(k)'
+                            //
+                            r1 = 1/a[k,k];
+                            for(i=1; i<=k-1; i++)
+                            {
+                                i2 = k-1;
+                                vv = -(r1*a[i,k]);
+                                for(i_=i; i_<=i2;i_++)
+                                {
+                                    a[i,i_] = a[i,i_] + vv*a[i_,k];
+                                }
+                            }
+                            
+                            //
+                            // Store U(k) in column k
+                            //
+                            i2 = k-1;
+                            for(i_=1; i_<=i2;i_++)
+                            {
+                                a[i_,k] = r1*a[i_,k];
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // 2-by-2 pivot block D(k): columns k and k-1 now hold
+                            //
+                            // ( W(k-1) W(k) ) = ( U(k-1) U(k) )*D(k)
+                            //
+                            // where U(k) and U(k-1) are the k-th and (k-1)-th columns
+                            // of U
+                            //
+                            // Perform a rank-2 update of A(1:k-2,1:k-2) as
+                            //
+                            // A := A - ( U(k-1) U(k) )*D(k)*( U(k-1) U(k) )'
+                            //    = A - ( W(k-1) W(k) )*inv(D(k))*( W(k-1) W(k) )'
+                            //
+                            if( k>2 )
+                            {
+                                d12 = a[k-1,k];
+                                d22 = a[k-1,k-1]/d12;
+                                d11 = a[k,k]/d12;
+                                t = 1/(d11*d22-1);
+                                d12 = t/d12;
+                                for(j=k-2; j>=1; j--)
+                                {
+                                    wkm1 = d12*(d11*a[j,k-1]-a[j,k]);
+                                    wk = d12*(d22*a[j,k]-a[j,k-1]);
+                                    for(i_=1; i_<=j;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wk*a[i_,k];
+                                    }
+                                    i1 = k-1;
+                                    for(i_=1; i_<=j;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wkm1*a[i_,i1];
+                                    }
+                                    a[j,k] = wk;
+                                    a[j,k-1] = wkm1;
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Store details of the interchanges in IPIV
+                    //
+                    if( kstep==1 )
+                    {
+                        pivots[k] = kp;
+                    }
+                    else
+                    {
+                        pivots[k] = -kp;
+                        pivots[k-1] = -kp;
+                    }
+                    
+                    //
+                    // Decrease K and return to the start of the main loop
+                    //
+                    k = k-kstep;
+                }
+            }
+            else
+            {
+                
+                //
+                // Factorize A as L*D*L' using the lower triangle of A
+                //
+                // K is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2
+                //
+                k = 1;
+                while( k<=n )
+                {
+                    kstep = 1;
+                    
+                    //
+                    // Determine rows and columns to be interchanged and whether
+                    // a 1-by-1 or 2-by-2 pivot block will be used
+                    //
+                    absakk = Math.Abs(a[k,k]);
+                    
+                    //
+                    // IMAX is the row-index of the largest off-diagonal element in
+                    // column K, and COLMAX is its absolute value
+                    //
+                    if( k<n )
+                    {
+                        imax = k+1;
+                        for(ii=k+2; ii<=n; ii++)
+                        {
+                            if( (double)(Math.Abs(a[ii,k]))>(double)(Math.Abs(a[imax,k])) )
+                            {
+                                imax = ii;
+                            }
+                        }
+                        colmax = Math.Abs(a[imax,k]);
+                    }
+                    else
+                    {
+                        colmax = 0;
+                    }
+                    if( (double)(Math.Max(absakk, colmax))==(double)(0) )
+                    {
+                        
+                        //
+                        // Column K is zero
+                        //
+                        kp = k;
+                    }
+                    else
+                    {
+                        if( (double)(absakk)>=(double)(alpha*colmax) )
+                        {
+                            
+                            //
+                            // no interchange, use 1-by-1 pivot block
+                            //
+                            kp = k;
+                        }
+                        else
+                        {
+                            
+                            //
+                            // JMAX is the column-index of the largest off-diagonal
+                            // element in row IMAX, and ROWMAX is its absolute value
+                            //
+                            jmax = k;
+                            for(ii=k+1; ii<=imax-1; ii++)
+                            {
+                                if( (double)(Math.Abs(a[imax,ii]))>(double)(Math.Abs(a[imax,jmax])) )
+                                {
+                                    jmax = ii;
+                                }
+                            }
+                            rowmax = Math.Abs(a[imax,jmax]);
+                            if( imax<n )
+                            {
+                                jmax = imax+1;
+                                for(ii=imax+2; ii<=n; ii++)
+                                {
+                                    if( (double)(Math.Abs(a[ii,imax]))>(double)(Math.Abs(a[jmax,imax])) )
+                                    {
+                                        jmax = ii;
+                                    }
+                                }
+                                rowmax = Math.Max(rowmax, Math.Abs(a[jmax,imax]));
+                            }
+                            vv = colmax/rowmax;
+                            if( (double)(absakk)>=(double)(alpha*colmax*vv) )
+                            {
+                                
+                                //
+                                // no interchange, use 1-by-1 pivot block
+                                //
+                                kp = k;
+                            }
+                            else
+                            {
+                                if( (double)(Math.Abs(a[imax,imax]))>=(double)(alpha*rowmax) )
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K and IMAX, use 1-by-1
+                                    // pivot block
+                                    //
+                                    kp = imax;
+                                }
+                                else
+                                {
+                                    
+                                    //
+                                    // interchange rows and columns K+1 and IMAX, use 2-by-2
+                                    // pivot block
+                                    //
+                                    kp = imax;
+                                    kstep = 2;
+                                }
+                            }
+                        }
+                        kk = k+kstep-1;
+                        if( kp!=kk )
+                        {
+                            
+                            //
+                            //              Interchange rows and columns KK and KP in the trailing
+                            //              submatrix A(k:n,k:n)
+                            //
+                            if( kp<n )
+                            {
+                                i1 = kp+1;
+                                for(i_=i1; i_<=n;i_++)
+                                {
+                                    temp[i_] = a[i_,kk];
+                                }
+                                for(i_=i1; i_<=n;i_++)
+                                {
+                                    a[i_,kk] = a[i_,kp];
+                                }
+                                for(i_=i1; i_<=n;i_++)
+                                {
+                                    a[i_,kp] = temp[i_];
+                                }
+                            }
+                            i1 = kk+1;
+                            i2 = kp-1;
+                            for(i_=i1; i_<=i2;i_++)
+                            {
+                                temp[i_] = a[i_,kk];
+                            }
+                            for(i_=i1; i_<=i2;i_++)
+                            {
+                                a[i_,kk] = a[kp,i_];
+                            }
+                            for(i_=i1; i_<=i2;i_++)
+                            {
+                                a[kp,i_] = temp[i_];
+                            }
+                            t = a[kk,kk];
+                            a[kk,kk] = a[kp,kp];
+                            a[kp,kp] = t;
+                            if( kstep==2 )
+                            {
+                                t = a[k+1,k];
+                                a[k+1,k] = a[kp,k];
+                                a[kp,k] = t;
+                            }
+                        }
+                        
+                        //
+                        // Update the trailing submatrix
+                        //
+                        if( kstep==1 )
+                        {
+                            
+                            //
+                            // 1-by-1 pivot block D(k): column k now holds
+                            //
+                            // W(k) = L(k)*D(k)
+                            //
+                            // where L(k) is the k-th column of L
+                            //
+                            if( k<n )
+                            {
+                                
+                                //
+                                // Perform a rank-1 update of A(k+1:n,k+1:n) as
+                                //
+                                // A := A - L(k)*D(k)*L(k)' = A - W(k)*(1/D(k))*W(k)'
+                                //
+                                d11 = 1/a[k,k];
+                                for(ii=k+1; ii<=n; ii++)
+                                {
+                                    i1 = k+1;
+                                    i2 = ii;
+                                    vv = -(d11*a[ii,k]);
+                                    for(i_=i1; i_<=i2;i_++)
+                                    {
+                                        a[ii,i_] = a[ii,i_] + vv*a[i_,k];
+                                    }
+                                }
+                                
+                                //
+                                // Store L(k) in column K
+                                //
+                                i1 = k+1;
+                                for(i_=i1; i_<=n;i_++)
+                                {
+                                    a[i_,k] = d11*a[i_,k];
+                                }
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // 2-by-2 pivot block D(k)
+                            //
+                            if( k<n-1 )
+                            {
+                                
+                                //
+                                // Perform a rank-2 update of A(k+2:n,k+2:n) as
+                                //
+                                // A := A - ( (A(k) A(k+1))*D(k)**(-1) ) * (A(k) A(k+1))'
+                                //
+                                // where L(k) and L(k+1) are the k-th and (k+1)-th
+                                // columns of L
+                                //
+                                d21 = a[k+1,k];
+                                d11 = a[k+1,k+1]/d21;
+                                d22 = a[k,k]/d21;
+                                t = 1/(d11*d22-1);
+                                d21 = t/d21;
+                                for(j=k+2; j<=n; j++)
+                                {
+                                    wk = d21*(d11*a[j,k]-a[j,k+1]);
+                                    wkp1 = d21*(d22*a[j,k+1]-a[j,k]);
+                                    ii = k+1;
+                                    for(i_=j; i_<=n;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wk*a[i_,k];
+                                    }
+                                    for(i_=j; i_<=n;i_++)
+                                    {
+                                        a[i_,j] = a[i_,j] - wkp1*a[i_,ii];
+                                    }
+                                    a[j,k] = wk;
+                                    a[j,k+1] = wkp1;
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Store details of the interchanges in IPIV
+                    //
+                    if( kstep==1 )
+                    {
+                        pivots[k] = kp;
+                    }
+                    else
+                    {
+                        pivots[k] = -kp;
+                        pivots[k+1] = -kp;
+                    }
+                    
+                    //
+                    // Increase K and return to the start of the main loop
+                    //
+                    k = k+kstep;
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/leastsquares.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/leastsquares.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/leastsquares.cs	(revision 2645)
@@ -0,0 +1,1305 @@
+/*************************************************************************
+Copyright (c) 2006-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class leastsquares
+    {
+        /*************************************************************************
+        Weighted approximation by arbitrary function basis in a space of arbitrary
+        dimension using linear least squares method.
+
+        Input parameters:
+            Y   -   array[0..N-1]
+                    It contains a set  of  function  values  in  N  points.  Space
+                    dimension  and  points  don't  matter.  Procedure  works  with
+                    function values in these points and values of basis  functions
+                    only.
+
+            W   -   array[0..N-1]
+                    It contains weights corresponding  to  function  values.  Each
+                    summand in square sum of approximation deviations  from  given
+                    values is multiplied by the square of corresponding weight.
+
+            FMatrix-a table of basis functions values, array[0..N-1, 0..M-1].
+                    FMatrix[I, J] - value of J-th basis function in I-th point.
+
+            N   -   number of points used. N>=1.
+            M   -   number of basis functions, M>=1.
+
+        Output parameters:
+            C   -   decomposition coefficients.
+                    Array of real numbers whose index goes from 0 to M-1.
+                    C[j] - j-th basis function coefficient.
+
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void buildgeneralleastsquares(ref double[] y,
+            ref double[] w,
+            ref double[,] fmatrix,
+            int n,
+            int m,
+            ref double[] c)
+        {
+            int i = 0;
+            int j = 0;
+            double[,] a = new double[0,0];
+            double[,] q = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] b = new double[0];
+            double[] tau = new double[0];
+            double[,] b2 = new double[0,0];
+            double[] tauq = new double[0];
+            double[] taup = new double[0];
+            double[] d = new double[0];
+            double[] e = new double[0];
+            bool isuppera = new bool();
+            int mi = 0;
+            int ni = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            mi = n;
+            ni = m;
+            c = new double[ni-1+1];
+            
+            //
+            // Initialize design matrix.
+            // Here we are making MI>=NI.
+            //
+            a = new double[ni+1, Math.Max(mi, ni)+1];
+            b = new double[Math.Max(mi, ni)+1];
+            for(i=1; i<=mi; i++)
+            {
+                b[i] = w[i-1]*y[i-1];
+            }
+            for(i=mi+1; i<=ni; i++)
+            {
+                b[i] = 0;
+            }
+            for(j=1; j<=ni; j++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=mi;i_++)
+                {
+                    a[j,i_] = fmatrix[i_+i1_,j-1];
+                }
+            }
+            for(j=1; j<=ni; j++)
+            {
+                for(i=mi+1; i<=ni; i++)
+                {
+                    a[j,i] = 0;
+                }
+            }
+            for(j=1; j<=ni; j++)
+            {
+                for(i=1; i<=mi; i++)
+                {
+                    a[j,i] = a[j,i]*w[i-1];
+                }
+            }
+            mi = Math.Max(mi, ni);
+            
+            //
+            // LQ-decomposition of A'
+            // B2 := Q*B
+            //
+            lq.lqdecomposition(ref a, ni, mi, ref tau);
+            lq.unpackqfromlq(ref a, ni, mi, ref tau, ni, ref q);
+            b2 = new double[1+1, ni+1];
+            for(j=1; j<=ni; j++)
+            {
+                b2[1,j] = 0;
+            }
+            for(i=1; i<=ni; i++)
+            {
+                v = 0.0;
+                for(i_=1; i_<=mi;i_++)
+                {
+                    v += b[i_]*q[i,i_];
+                }
+                b2[1,i] = v;
+            }
+            
+            //
+            // Back from A' to A
+            // Making cols(A)=rows(A)
+            //
+            for(i=1; i<=ni-1; i++)
+            {
+                for(i_=i+1; i_<=ni;i_++)
+                {
+                    a[i,i_] = a[i_,i];
+                }
+            }
+            for(i=2; i<=ni; i++)
+            {
+                for(j=1; j<=i-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            
+            //
+            // Bidiagonal decomposition of A
+            // A = Q * d2 * P'
+            // B2 := (Q'*B2')'
+            //
+            bidiagonal.tobidiagonal(ref a, ni, ni, ref tauq, ref taup);
+            bidiagonal.multiplybyqfrombidiagonal(ref a, ni, ni, ref tauq, ref b2, 1, ni, true, false);
+            bidiagonal.unpackptfrombidiagonal(ref a, ni, ni, ref taup, ni, ref vt);
+            bidiagonal.unpackdiagonalsfrombidiagonal(ref a, ni, ni, ref isuppera, ref d, ref e);
+            
+            //
+            // Singular value decomposition of A
+            // A = U * d * V'
+            // B2 := (U'*B2')'
+            //
+            if( !bdsvd.bidiagonalsvddecomposition(ref d, e, ni, isuppera, false, ref b2, 1, ref q, 0, ref vt, ni) )
+            {
+                for(i=0; i<=ni-1; i++)
+                {
+                    c[i] = 0;
+                }
+                return;
+            }
+            
+            //
+            // B2 := (d^(-1) * B2')'
+            //
+            if( (double)(d[1])!=(double)(0) )
+            {
+                for(i=1; i<=ni; i++)
+                {
+                    if( (double)(d[i])>(double)(AP.Math.MachineEpsilon*10*Math.Sqrt(ni)*d[1]) )
+                    {
+                        b2[1,i] = b2[1,i]/d[i];
+                    }
+                    else
+                    {
+                        b2[1,i] = 0;
+                    }
+                }
+            }
+            
+            //
+            // B := (V * B2')'
+            //
+            for(i=1; i<=ni; i++)
+            {
+                b[i] = 0;
+            }
+            for(i=1; i<=ni; i++)
+            {
+                v = b2[1,i];
+                for(i_=1; i_<=ni;i_++)
+                {
+                    b[i_] = b[i_] + v*vt[i,i_];
+                }
+            }
+            
+            //
+            // Out
+            //
+            for(i=1; i<=ni; i++)
+            {
+                c[i-1] = b[i];
+            }
+        }
+
+
+        /*************************************************************************
+        Linear approximation using least squares method
+
+        The subroutine calculates coefficients of  the  line  approximating  given
+        function.
+
+        Input parameters:
+            X   -   array[0..N-1], it contains a set of abscissas.
+            Y   -   array[0..N-1], function values.
+            N   -   number of points, N>=1
+
+        Output parameters:
+            a, b-   coefficients of linear approximation a+b*t
+
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void buildlinearleastsquares(ref double[] x,
+            ref double[] y,
+            int n,
+            ref double a,
+            ref double b)
+        {
+            double pp = 0;
+            double qq = 0;
+            double pq = 0;
+            double b1 = 0;
+            double b2 = 0;
+            double d1 = 0;
+            double d2 = 0;
+            double t1 = 0;
+            double t2 = 0;
+            double phi = 0;
+            double c = 0;
+            double s = 0;
+            double m = 0;
+            int i = 0;
+
+            pp = n;
+            qq = 0;
+            pq = 0;
+            b1 = 0;
+            b2 = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                pq = pq+x[i];
+                qq = qq+AP.Math.Sqr(x[i]);
+                b1 = b1+y[i];
+                b2 = b2+x[i]*y[i];
+            }
+            phi = Math.Atan2(2*pq, qq-pp)/2;
+            c = Math.Cos(phi);
+            s = Math.Sin(phi);
+            d1 = AP.Math.Sqr(c)*pp+AP.Math.Sqr(s)*qq-2*s*c*pq;
+            d2 = AP.Math.Sqr(s)*pp+AP.Math.Sqr(c)*qq+2*s*c*pq;
+            if( (double)(Math.Abs(d1))>(double)(Math.Abs(d2)) )
+            {
+                m = Math.Abs(d1);
+            }
+            else
+            {
+                m = Math.Abs(d2);
+            }
+            t1 = c*b1-s*b2;
+            t2 = s*b1+c*b2;
+            if( (double)(Math.Abs(d1))>(double)(m*AP.Math.MachineEpsilon*1000) )
+            {
+                t1 = t1/d1;
+            }
+            else
+            {
+                t1 = 0;
+            }
+            if( (double)(Math.Abs(d2))>(double)(m*AP.Math.MachineEpsilon*1000) )
+            {
+                t2 = t2/d2;
+            }
+            else
+            {
+                t2 = 0;
+            }
+            a = c*t1+s*t2;
+            b = -(s*t1)+c*t2;
+        }
+
+
+        /*************************************************************************
+        Weighted cubic spline approximation using linear least squares
+
+        Input parameters:
+            X   -   array[0..N-1], abscissas
+            Y   -   array[0..N-1], function values
+            W   -   array[0..N-1], weights.
+            A, B-   interval to build splines in.
+            N   -   number of points used. N>=1.
+            M   -   number of basic splines, M>=2.
+
+        Output parameters:
+            CTbl-   coefficients table to be used by SplineInterpolation function.
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void buildsplineleastsquares(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            double a,
+            double b,
+            int n,
+            int m,
+            ref double[] ctbl)
+        {
+            int i = 0;
+            int j = 0;
+            double[,] ma = new double[0,0];
+            double[,] q = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] mb = new double[0];
+            double[] tau = new double[0];
+            double[,] b2 = new double[0,0];
+            double[] tauq = new double[0];
+            double[] taup = new double[0];
+            double[] d = new double[0];
+            double[] e = new double[0];
+            bool isuppera = new bool();
+            int mi = 0;
+            int ni = 0;
+            double v = 0;
+            double[] sx = new double[0];
+            double[] sy = new double[0];
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(m>=2, "BuildSplineLeastSquares: M is too small!");
+            mi = n;
+            ni = m;
+            sx = new double[ni-1+1];
+            sy = new double[ni-1+1];
+            
+            //
+            // Initializing design matrix
+            // Here we are making MI>=NI
+            //
+            ma = new double[ni+1, Math.Max(mi, ni)+1];
+            mb = new double[Math.Max(mi, ni)+1];
+            for(j=0; j<=ni-1; j++)
+            {
+                sx[j] = a+(b-a)*j/(ni-1);
+            }
+            for(j=0; j<=ni-1; j++)
+            {
+                for(i=0; i<=ni-1; i++)
+                {
+                    sy[i] = 0;
+                }
+                sy[j] = 1;
+                spline3.buildcubicspline(sx, sy, ni, 0, 0.0, 0, 0.0, ref ctbl);
+                for(i=0; i<=mi-1; i++)
+                {
+                    ma[j+1,i+1] = w[i]*spline3.splineinterpolation(ref ctbl, x[i]);
+                }
+            }
+            for(j=1; j<=ni; j++)
+            {
+                for(i=mi+1; i<=ni; i++)
+                {
+                    ma[j,i] = 0;
+                }
+            }
+            
+            //
+            // Initializing right part
+            //
+            for(i=0; i<=mi-1; i++)
+            {
+                mb[i+1] = w[i]*y[i];
+            }
+            for(i=mi+1; i<=ni; i++)
+            {
+                mb[i] = 0;
+            }
+            mi = Math.Max(mi, ni);
+            
+            //
+            // LQ-decomposition of A'
+            // B2 := Q*B
+            //
+            lq.lqdecomposition(ref ma, ni, mi, ref tau);
+            lq.unpackqfromlq(ref ma, ni, mi, ref tau, ni, ref q);
+            b2 = new double[1+1, ni+1];
+            for(j=1; j<=ni; j++)
+            {
+                b2[1,j] = 0;
+            }
+            for(i=1; i<=ni; i++)
+            {
+                v = 0.0;
+                for(i_=1; i_<=mi;i_++)
+                {
+                    v += mb[i_]*q[i,i_];
+                }
+                b2[1,i] = v;
+            }
+            
+            //
+            // Back from A' to A
+            // Making cols(A)=rows(A)
+            //
+            for(i=1; i<=ni-1; i++)
+            {
+                for(i_=i+1; i_<=ni;i_++)
+                {
+                    ma[i,i_] = ma[i_,i];
+                }
+            }
+            for(i=2; i<=ni; i++)
+            {
+                for(j=1; j<=i-1; j++)
+                {
+                    ma[i,j] = 0;
+                }
+            }
+            
+            //
+            // Bidiagonal decomposition of A
+            // A = Q * d2 * P'
+            // B2 := (Q'*B2')'
+            //
+            bidiagonal.tobidiagonal(ref ma, ni, ni, ref tauq, ref taup);
+            bidiagonal.multiplybyqfrombidiagonal(ref ma, ni, ni, ref tauq, ref b2, 1, ni, true, false);
+            bidiagonal.unpackptfrombidiagonal(ref ma, ni, ni, ref taup, ni, ref vt);
+            bidiagonal.unpackdiagonalsfrombidiagonal(ref ma, ni, ni, ref isuppera, ref d, ref e);
+            
+            //
+            // Singular value decomposition of A
+            // A = U * d * V'
+            // B2 := (U'*B2')'
+            //
+            if( !bdsvd.bidiagonalsvddecomposition(ref d, e, ni, isuppera, false, ref b2, 1, ref q, 0, ref vt, ni) )
+            {
+                for(i=1; i<=ni; i++)
+                {
+                    d[i] = 0;
+                    b2[1,i] = 0;
+                    for(j=1; j<=ni; j++)
+                    {
+                        if( i==j )
+                        {
+                            vt[i,j] = 1;
+                        }
+                        else
+                        {
+                            vt[i,j] = 0;
+                        }
+                    }
+                }
+                b2[1,1] = 1;
+            }
+            
+            //
+            // B2 := (d^(-1) * B2')'
+            //
+            for(i=1; i<=ni; i++)
+            {
+                if( (double)(d[i])>(double)(AP.Math.MachineEpsilon*10*Math.Sqrt(ni)*d[1]) )
+                {
+                    b2[1,i] = b2[1,i]/d[i];
+                }
+                else
+                {
+                    b2[1,i] = 0;
+                }
+            }
+            
+            //
+            // B := (V * B2')'
+            //
+            for(i=1; i<=ni; i++)
+            {
+                mb[i] = 0;
+            }
+            for(i=1; i<=ni; i++)
+            {
+                v = b2[1,i];
+                for(i_=1; i_<=ni;i_++)
+                {
+                    mb[i_] = mb[i_] + v*vt[i,i_];
+                }
+            }
+            
+            //
+            // Forming result spline
+            //
+            for(i=0; i<=ni-1; i++)
+            {
+                sy[i] = mb[i+1];
+            }
+            spline3.buildcubicspline(sx, sy, ni, 0, 0.0, 0, 0.0, ref ctbl);
+        }
+
+
+        /*************************************************************************
+        Polynomial approximation using least squares method
+
+        The subroutine calculates coefficients  of  the  polynomial  approximating
+        given function. It is recommended to use this function only if you need to
+        obtain coefficients of approximation polynomial. If you have to build  and
+        calculate polynomial approximation (NOT coefficients), it's better to  use
+        BuildChebyshevLeastSquares      subroutine     in     combination     with
+        CalculateChebyshevLeastSquares   subroutine.   The   result  of  Chebyshev
+        polynomial approximation is equivalent to the result obtained using powers
+        of X, but has higher  accuracy  due  to  better  numerical  properties  of
+        Chebyshev polynomials.
+
+        Input parameters:
+            X   -   array[0..N-1], abscissas
+            Y   -   array[0..N-1], function values
+            N   -   number of points, N>=1
+            M   -   order of polynomial required, M>=0
+
+        Output parameters:
+            C   -   approximating polynomial coefficients, array[0..M],
+                    C[i] - coefficient at X^i.
+
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void buildpolynomialleastsquares(ref double[] x,
+            ref double[] y,
+            int n,
+            int m,
+            ref double[] c)
+        {
+            double[] ctbl = new double[0];
+            double[] w = new double[0];
+            double[] c1 = new double[0];
+            double maxx = 0;
+            double minx = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            double e = 0;
+            double d = 0;
+            double l1 = 0;
+            double l2 = 0;
+            double[] z2 = new double[0];
+            double[] z1 = new double[0];
+
+            
+            //
+            // Initialize
+            //
+            maxx = x[0];
+            minx = x[0];
+            for(i=1; i<=n-1; i++)
+            {
+                if( (double)(x[i])>(double)(maxx) )
+                {
+                    maxx = x[i];
+                }
+                if( (double)(x[i])<(double)(minx) )
+                {
+                    minx = x[i];
+                }
+            }
+            if( (double)(minx)==(double)(maxx) )
+            {
+                minx = minx-0.5;
+                maxx = maxx+0.5;
+            }
+            w = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                w[i] = 1;
+            }
+            
+            //
+            // Build Chebyshev approximation
+            //
+            buildchebyshevleastsquares(ref x, ref y, ref w, minx, maxx, n, m, ref ctbl);
+            
+            //
+            // From Chebyshev to powers of X
+            //
+            c1 = new double[m+1];
+            for(i=0; i<=m; i++)
+            {
+                c1[i] = 0;
+            }
+            d = 0;
+            for(i=0; i<=m; i++)
+            {
+                for(k=i; k<=m; k++)
+                {
+                    e = c1[k];
+                    c1[k] = 0;
+                    if( i<=1 & k==i )
+                    {
+                        c1[k] = 1;
+                    }
+                    else
+                    {
+                        if( i!=0 )
+                        {
+                            c1[k] = 2*d;
+                        }
+                        if( k>i+1 )
+                        {
+                            c1[k] = c1[k]-c1[k-2];
+                        }
+                    }
+                    d = e;
+                }
+                d = c1[i];
+                e = 0;
+                k = i;
+                while( k<=m )
+                {
+                    e = e+c1[k]*ctbl[k];
+                    k = k+2;
+                }
+                c1[i] = e;
+            }
+            
+            //
+            // Linear translation
+            //
+            l1 = 2/(ctbl[m+2]-ctbl[m+1]);
+            l2 = -(2*ctbl[m+1]/(ctbl[m+2]-ctbl[m+1]))-1;
+            c = new double[m+1];
+            z2 = new double[m+1];
+            z1 = new double[m+1];
+            c[0] = c1[0];
+            z1[0] = 1;
+            z2[0] = 1;
+            for(i=1; i<=m; i++)
+            {
+                z2[i] = 1;
+                z1[i] = l2*z1[i-1];
+                c[0] = c[0]+c1[i]*z1[i];
+            }
+            for(j=1; j<=m; j++)
+            {
+                z2[0] = l1*z2[0];
+                c[j] = c1[j]*z2[0];
+                for(i=j+1; i<=m; i++)
+                {
+                    k = i-j;
+                    z2[k] = l1*z2[k]+z2[k-1];
+                    c[j] = c[j]+c1[i]*z2[k]*z1[k];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Chebyshev polynomial approximation using least squares method.
+
+        The algorithm reduces interval [A, B] to the interval [-1,1], then  builds
+        least squares approximation using Chebyshev polynomials.
+
+        Input parameters:
+            X   -   array[0..N-1], abscissas
+            Y   -   array[0..N-1], function values
+            W   -   array[0..N-1], weights
+            A, B-   interval to build approximating polynomials in.
+            N   -   number of points used. N>=1.
+            M   -   order of polynomial, M>=0. This parameter is passed into
+                    CalculateChebyshevLeastSquares function.
+
+        Output parameters:
+            CTbl - coefficient table. This parameter is passed into
+                    CalculateChebyshevLeastSquares function.
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void buildchebyshevleastsquares(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            double a,
+            double b,
+            int n,
+            int m,
+            ref double[] ctbl)
+        {
+            int i = 0;
+            int j = 0;
+            double[,] ma = new double[0,0];
+            double[,] q = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] mb = new double[0];
+            double[] tau = new double[0];
+            double[,] b2 = new double[0,0];
+            double[] tauq = new double[0];
+            double[] taup = new double[0];
+            double[] d = new double[0];
+            double[] e = new double[0];
+            bool isuppera = new bool();
+            int mi = 0;
+            int ni = 0;
+            double v = 0;
+            int i_ = 0;
+
+            mi = n;
+            ni = m+1;
+            
+            //
+            // Initializing design matrix
+            // Here we are making MI>=NI
+            //
+            ma = new double[ni+1, Math.Max(mi, ni)+1];
+            mb = new double[Math.Max(mi, ni)+1];
+            for(j=1; j<=ni; j++)
+            {
+                for(i=1; i<=mi; i++)
+                {
+                    v = 2*(x[i-1]-a)/(b-a)-1;
+                    if( j==1 )
+                    {
+                        ma[j,i] = 1.0;
+                    }
+                    if( j==2 )
+                    {
+                        ma[j,i] = v;
+                    }
+                    if( j>2 )
+                    {
+                        ma[j,i] = 2.0*v*ma[j-1,i]-ma[j-2,i];
+                    }
+                }
+            }
+            for(j=1; j<=ni; j++)
+            {
+                for(i=1; i<=mi; i++)
+                {
+                    ma[j,i] = w[i-1]*ma[j,i];
+                }
+            }
+            for(j=1; j<=ni; j++)
+            {
+                for(i=mi+1; i<=ni; i++)
+                {
+                    ma[j,i] = 0;
+                }
+            }
+            
+            //
+            // Initializing right part
+            //
+            for(i=0; i<=mi-1; i++)
+            {
+                mb[i+1] = w[i]*y[i];
+            }
+            for(i=mi+1; i<=ni; i++)
+            {
+                mb[i] = 0;
+            }
+            mi = Math.Max(mi, ni);
+            
+            //
+            // LQ-decomposition of A'
+            // B2 := Q*B
+            //
+            lq.lqdecomposition(ref ma, ni, mi, ref tau);
+            lq.unpackqfromlq(ref ma, ni, mi, ref tau, ni, ref q);
+            b2 = new double[1+1, ni+1];
+            for(j=1; j<=ni; j++)
+            {
+                b2[1,j] = 0;
+            }
+            for(i=1; i<=ni; i++)
+            {
+                v = 0.0;
+                for(i_=1; i_<=mi;i_++)
+                {
+                    v += mb[i_]*q[i,i_];
+                }
+                b2[1,i] = v;
+            }
+            
+            //
+            // Back from A' to A
+            // Making cols(A)=rows(A)
+            //
+            for(i=1; i<=ni-1; i++)
+            {
+                for(i_=i+1; i_<=ni;i_++)
+                {
+                    ma[i,i_] = ma[i_,i];
+                }
+            }
+            for(i=2; i<=ni; i++)
+            {
+                for(j=1; j<=i-1; j++)
+                {
+                    ma[i,j] = 0;
+                }
+            }
+            
+            //
+            // Bidiagonal decomposition of A
+            // A = Q * d2 * P'
+            // B2 := (Q'*B2')'
+            //
+            bidiagonal.tobidiagonal(ref ma, ni, ni, ref tauq, ref taup);
+            bidiagonal.multiplybyqfrombidiagonal(ref ma, ni, ni, ref tauq, ref b2, 1, ni, true, false);
+            bidiagonal.unpackptfrombidiagonal(ref ma, ni, ni, ref taup, ni, ref vt);
+            bidiagonal.unpackdiagonalsfrombidiagonal(ref ma, ni, ni, ref isuppera, ref d, ref e);
+            
+            //
+            // Singular value decomposition of A
+            // A = U * d * V'
+            // B2 := (U'*B2')'
+            //
+            if( !bdsvd.bidiagonalsvddecomposition(ref d, e, ni, isuppera, false, ref b2, 1, ref q, 0, ref vt, ni) )
+            {
+                for(i=1; i<=ni; i++)
+                {
+                    d[i] = 0;
+                    b2[1,i] = 0;
+                    for(j=1; j<=ni; j++)
+                    {
+                        if( i==j )
+                        {
+                            vt[i,j] = 1;
+                        }
+                        else
+                        {
+                            vt[i,j] = 0;
+                        }
+                    }
+                }
+                b2[1,1] = 1;
+            }
+            
+            //
+            // B2 := (d^(-1) * B2')'
+            //
+            for(i=1; i<=ni; i++)
+            {
+                if( (double)(d[i])>(double)(AP.Math.MachineEpsilon*10*Math.Sqrt(ni)*d[1]) )
+                {
+                    b2[1,i] = b2[1,i]/d[i];
+                }
+                else
+                {
+                    b2[1,i] = 0;
+                }
+            }
+            
+            //
+            // B := (V * B2')'
+            //
+            for(i=1; i<=ni; i++)
+            {
+                mb[i] = 0;
+            }
+            for(i=1; i<=ni; i++)
+            {
+                v = b2[1,i];
+                for(i_=1; i_<=ni;i_++)
+                {
+                    mb[i_] = mb[i_] + v*vt[i,i_];
+                }
+            }
+            
+            //
+            // Forming result
+            //
+            ctbl = new double[ni+1+1];
+            for(i=1; i<=ni; i++)
+            {
+                ctbl[i-1] = mb[i];
+            }
+            ctbl[ni] = a;
+            ctbl[ni+1] = b;
+        }
+
+
+        /*************************************************************************
+        Weighted Chebyshev polynomial constrained least squares approximation.
+
+        The algorithm reduces [A,B] to [-1,1] and builds the Chebyshev polynomials
+        series by approximating a given function using the least squares method.
+
+        Input parameters:
+            X   -   abscissas, array[0..N-1]
+            Y   -   function values, array[0..N-1]
+            W   -   weights, array[0..N-1].  Each  item  in  the  squared  sum  of
+                    deviations from given values is  multiplied  by  a  square  of
+                    corresponding weight.
+            A, B-   interval in which the approximating polynomials are built.
+            N   -   number of points, N>0.
+            XC, YC, DC-
+                    constraints (see description below)., array[0..NC-1]
+            NC  -   number of constraints. 0 <= NC < M+1.
+            M   -   degree of polynomial, M>=0. This parameter is passed into  the
+                    CalculateChebyshevLeastSquares subroutine.
+
+        Output parameters:
+            CTbl-   coefficient  table.  This  parameter  is   passed   into   the
+                    CalculateChebyshevLeastSquares subroutine.
+
+        Result:
+            True, if the algorithm succeeded.
+            False, if the internal singular value decomposition subroutine  hasn't
+        converged or the given constraints could not be met  simultaneously  (e.g.
+        P(0)=0 è P(0)=1).
+
+        Specifying constraints:
+            This subroutine can solve  the  problem  having  constrained  function
+        values or its derivatives in several points. NC specifies  the  number  of
+        constraints, DC - the type of constraints, XC and YC - constraints as such.
+        Thus, for each i from 0 to NC-1 the following constraint is given:
+            P(xc[i]) = yc[i],       if DC[i]=0
+        or
+            d/dx(P(xc[i])) = yc[i], if DC[i]=1
+        (here P(x) is approximating polynomial).
+            This version of the subroutine supports only either polynomial or  its
+        derivative value constraints.  If  DC[i]  is  not  equal  to  0 and 1, the
+        subroutine will be aborted. The number of constraints should be less  than
+        the number of degrees of freedom of approximating  polynomial  -  M+1  (at
+        that, it could be equal to 0).
+
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static bool buildchebyshevleastsquaresconstrained(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            double a,
+            double b,
+            int n,
+            ref double[] xc,
+            ref double[] yc,
+            ref int[] dc,
+            int nc,
+            int m,
+            ref double[] ctbl)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            int reducedsize = 0;
+            double[,] designmatrix = new double[0,0];
+            double[] rightpart = new double[0];
+            double[,] cmatrix = new double[0,0];
+            double[,] c = new double[0,0];
+            double[,] u = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] d = new double[0];
+            double[] cr = new double[0];
+            double[] ws = new double[0];
+            double[] tj = new double[0];
+            double[] uj = new double[0];
+            double[] dtj = new double[0];
+            double[] tmp = new double[0];
+            double[] tmp2 = new double[0];
+            double[,] tmpmatrix = new double[0,0];
+            double v = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0);
+            System.Diagnostics.Debug.Assert(m>=0);
+            System.Diagnostics.Debug.Assert(nc>=0 & nc<m+1);
+            result = true;
+            
+            //
+            // Initialize design matrix and right part.
+            // Add fictional rows if needed to ensure that N>=M+1.
+            //
+            designmatrix = new double[Math.Max(n, m+1)+1, m+1+1];
+            rightpart = new double[Math.Max(n, m+1)+1];
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=m+1; j++)
+                {
+                    v = 2*(x[i-1]-a)/(b-a)-1;
+                    if( j==1 )
+                    {
+                        designmatrix[i,j] = 1.0;
+                    }
+                    if( j==2 )
+                    {
+                        designmatrix[i,j] = v;
+                    }
+                    if( j>2 )
+                    {
+                        designmatrix[i,j] = 2.0*v*designmatrix[i,j-1]-designmatrix[i,j-2];
+                    }
+                }
+            }
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=m+1; j++)
+                {
+                    designmatrix[i,j] = w[i-1]*designmatrix[i,j];
+                }
+            }
+            for(i=n+1; i<=m+1; i++)
+            {
+                for(j=1; j<=m+1; j++)
+                {
+                    designmatrix[i,j] = 0;
+                }
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                rightpart[i+1] = w[i]*y[i];
+            }
+            for(i=n+1; i<=m+1; i++)
+            {
+                rightpart[i] = 0;
+            }
+            n = Math.Max(n, m+1);
+            
+            //
+            // Now N>=M+1 and we are ready to the next stage.
+            // Handle constraints.
+            // Represent feasible set of coefficients as x = C*t + d
+            //
+            c = new double[m+1+1, m+1+1];
+            d = new double[m+1+1];
+            if( nc==0 )
+            {
+                
+                //
+                // No constraints
+                //
+                for(i=1; i<=m+1; i++)
+                {
+                    for(j=1; j<=m+1; j++)
+                    {
+                        c[i,j] = 0;
+                    }
+                    d[i] = 0;
+                }
+                for(i=1; i<=m+1; i++)
+                {
+                    c[i,i] = 1;
+                }
+                reducedsize = m+1;
+            }
+            else
+            {
+                
+                //
+                // Constraints are present.
+                // Fill constraints matrix CMatrix and solve CMatrix*x = cr.
+                //
+                cmatrix = new double[nc+1, m+1+1];
+                cr = new double[nc+1];
+                tj = new double[m+1];
+                uj = new double[m+1];
+                dtj = new double[m+1];
+                for(i=0; i<=nc-1; i++)
+                {
+                    v = 2*(xc[i]-a)/(b-a)-1;
+                    for(j=0; j<=m; j++)
+                    {
+                        if( j==0 )
+                        {
+                            tj[j] = 1;
+                            uj[j] = 1;
+                            dtj[j] = 0;
+                        }
+                        if( j==1 )
+                        {
+                            tj[j] = v;
+                            uj[j] = 2*v;
+                            dtj[j] = 1;
+                        }
+                        if( j>1 )
+                        {
+                            tj[j] = 2*v*tj[j-1]-tj[j-2];
+                            uj[j] = 2*v*uj[j-1]-uj[j-2];
+                            dtj[j] = j*uj[j-1];
+                        }
+                        System.Diagnostics.Debug.Assert(dc[i]==0 | dc[i]==1);
+                        if( dc[i]==0 )
+                        {
+                            cmatrix[i+1,j+1] = tj[j];
+                        }
+                        if( dc[i]==1 )
+                        {
+                            cmatrix[i+1,j+1] = dtj[j];
+                        }
+                    }
+                    cr[i+1] = yc[i];
+                }
+                
+                //
+                // Solve CMatrix*x = cr.
+                // Fill C and d:
+                // 1. SVD: CMatrix = U * WS * V^T
+                // 2. C := V[1:M+1,NC+1:M+1]
+                // 3. tmp := WS^-1 * U^T * cr
+                // 4. d := V[1:M+1,1:NC] * tmp
+                //
+                if( !svd.svddecomposition(cmatrix, nc, m+1, 2, 2, 2, ref ws, ref u, ref vt) )
+                {
+                    result = false;
+                    return result;
+                }
+                if( (double)(ws[1])==(double)(0) | (double)(ws[nc])<=(double)(AP.Math.MachineEpsilon*10*Math.Sqrt(nc)*ws[1]) )
+                {
+                    result = false;
+                    return result;
+                }
+                c = new double[m+1+1, m+1-nc+1];
+                d = new double[m+1+1];
+                for(i=1; i<=m+1-nc; i++)
+                {
+                    for(i_=1; i_<=m+1;i_++)
+                    {
+                        c[i_,i] = vt[nc+i,i_];
+                    }
+                }
+                tmp = new double[nc+1];
+                for(i=1; i<=nc; i++)
+                {
+                    v = 0.0;
+                    for(i_=1; i_<=nc;i_++)
+                    {
+                        v += u[i_,i]*cr[i_];
+                    }
+                    tmp[i] = v/ws[i];
+                }
+                for(i=1; i<=m+1; i++)
+                {
+                    d[i] = 0;
+                }
+                for(i=1; i<=nc; i++)
+                {
+                    v = tmp[i];
+                    for(i_=1; i_<=m+1;i_++)
+                    {
+                        d[i_] = d[i_] + v*vt[i,i_];
+                    }
+                }
+                
+                //
+                // Reduce problem:
+                // 1. RightPart := RightPart - DesignMatrix*d
+                // 2. DesignMatrix := DesignMatrix*C
+                //
+                for(i=1; i<=n; i++)
+                {
+                    v = 0.0;
+                    for(i_=1; i_<=m+1;i_++)
+                    {
+                        v += designmatrix[i,i_]*d[i_];
+                    }
+                    rightpart[i] = rightpart[i]-v;
+                }
+                reducedsize = m+1-nc;
+                tmpmatrix = new double[n+1, reducedsize+1];
+                tmp = new double[n+1];
+                blas.matrixmatrixmultiply(ref designmatrix, 1, n, 1, m+1, false, ref c, 1, m+1, 1, reducedsize, false, 1.0, ref tmpmatrix, 1, n, 1, reducedsize, 0.0, ref tmp);
+                blas.copymatrix(ref tmpmatrix, 1, n, 1, reducedsize, ref designmatrix, 1, n, 1, reducedsize);
+            }
+            
+            //
+            // Solve reduced problem DesignMatrix*t = RightPart.
+            //
+            if( !svd.svddecomposition(designmatrix, n, reducedsize, 1, 1, 2, ref ws, ref u, ref vt) )
+            {
+                result = false;
+                return result;
+            }
+            tmp = new double[reducedsize+1];
+            tmp2 = new double[reducedsize+1];
+            for(i=1; i<=reducedsize; i++)
+            {
+                tmp[i] = 0;
+            }
+            for(i=1; i<=n; i++)
+            {
+                v = rightpart[i];
+                for(i_=1; i_<=reducedsize;i_++)
+                {
+                    tmp[i_] = tmp[i_] + v*u[i,i_];
+                }
+            }
+            for(i=1; i<=reducedsize; i++)
+            {
+                if( (double)(ws[i])!=(double)(0) & (double)(ws[i])>(double)(AP.Math.MachineEpsilon*10*Math.Sqrt(nc)*ws[1]) )
+                {
+                    tmp[i] = tmp[i]/ws[i];
+                }
+                else
+                {
+                    tmp[i] = 0;
+                }
+            }
+            for(i=1; i<=reducedsize; i++)
+            {
+                tmp2[i] = 0;
+            }
+            for(i=1; i<=reducedsize; i++)
+            {
+                v = tmp[i];
+                for(i_=1; i_<=reducedsize;i_++)
+                {
+                    tmp2[i_] = tmp2[i_] + v*vt[i,i_];
+                }
+            }
+            
+            //
+            // Solution is in the tmp2.
+            // Transform it from t to x.
+            //
+            ctbl = new double[m+2+1];
+            for(i=1; i<=m+1; i++)
+            {
+                v = 0.0;
+                for(i_=1; i_<=reducedsize;i_++)
+                {
+                    v += c[i,i_]*tmp2[i_];
+                }
+                ctbl[i-1] = v+d[i];
+            }
+            ctbl[m+1] = a;
+            ctbl[m+2] = b;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Calculation of a Chebyshev  polynomial  obtained   during  least  squares
+        approximaion at the given point.
+
+        Input parameters:
+            M   -   order of polynomial (parameter of the
+                    BuildChebyshevLeastSquares function).
+            A   -   coefficient table.
+                    A[0..M] contains coefficients of the i-th Chebyshev polynomial.
+                    A[M+1] contains left boundary of approximation interval.
+                    A[M+2] contains right boundary of approximation interval.
+            X   -   point to perform calculations in.
+
+        The result is the value at the given point.
+
+        It should be noted that array A contains coefficients  of  the  Chebyshev
+        polynomials defined on interval [-1,1].   Argument  is  reduced  to  this
+        interval before calculating polynomial value.
+          -- ALGLIB --
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static double calculatechebyshevleastsquares(int m,
+            ref double[] a,
+            double x)
+        {
+            double result = 0;
+            double b1 = 0;
+            double b2 = 0;
+            int i = 0;
+
+            x = 2*(x-a[m+1])/(a[m+2]-a[m+1])-1;
+            b1 = 0;
+            b2 = 0;
+            i = m;
+            do
+            {
+                result = 2*x*b1-b2+a[i];
+                b2 = b1;
+                b1 = result;
+                i = i-1;
+            }
+            while( i>=0 );
+            result = result-x*b2;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/legendre.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/legendre.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/legendre.cs	(revision 2645)
@@ -0,0 +1,130 @@
+/*************************************************************************
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class legendre
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static double legendrecalculate(int n,
+            double x)
+        {
+            double result = 0;
+            double a = 0;
+            double b = 0;
+            int i = 0;
+
+            result = 1;
+            a = 1;
+            b = x;
+            if( n==0 )
+            {
+                result = a;
+                return result;
+            }
+            if( n==1 )
+            {
+                result = b;
+                return result;
+            }
+            for(i=2; i<=n; i++)
+            {
+                result = ((2*i-1)*x*b-(i-1)*a)/i;
+                a = b;
+                b = result;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Summation of Legendre polynomials using Clenshaws recurrence formula.
+
+        This routine calculates
+            c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x)
+
+        Parameters:
+            n   -   degree, n>=0
+            x   -   argument
+
+        Result:
+            the value of the Legendre polynomial at x
+        *************************************************************************/
+        public static double legendresum(ref double[] c,
+            int n,
+            double x)
+        {
+            double result = 0;
+            double b1 = 0;
+            double b2 = 0;
+            int i = 0;
+
+            b1 = 0;
+            b2 = 0;
+            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;
+        }
+
+
+        /*************************************************************************
+        Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N
+
+        Input parameters:
+            N   -   polynomial degree, n>=0
+
+        Output parameters:
+            C   -   coefficients
+        *************************************************************************/
+        public static void legendrecoefficients(int n,
+            ref double[] c)
+        {
+            int i = 0;
+
+            c = new double[n+1];
+            for(i=0; i<=n; i++)
+            {
+                c[i] = 0;
+            }
+            c[n] = 1;
+            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));
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/linreg.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/linreg.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/linreg.cs	(revision 2645)
@@ -0,0 +1,1333 @@
+/*************************************************************************
+Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class linreg
+    {
+        public struct linearmodel
+        {
+            public double[] w;
+        };
+
+
+        /*************************************************************************
+        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.
+        *************************************************************************/
+        public struct lrreport
+        {
+            public double[,] c;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+            public double cvrmserror;
+            public double cvavgerror;
+            public double cvavgrelerror;
+            public int ncvdefects;
+            public int[] cvdefects;
+        };
+
+
+
+
+        public const int lrvnum = 5;
+
+
+        /*************************************************************************
+        Linear regression
+
+        Subroutine builds model:
+
+            Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N)
+
+        and model found in ALGLIB format, covariation matrix, training set  errors
+        (rms,  average,  average  relative)   and  leave-one-out  cross-validation
+        estimate of the generalization error. CV  estimate calculated  using  fast
+        algorithm with O(NPoints*NVars) complexity.
+
+        When  covariation  matrix  is  calculated  standard deviations of function
+        values are assumed to be equal to RMS error on the training set.
+
+        INPUT PARAMETERS:
+            XY          -   training set, array [0..NPoints-1,0..NVars]:
+                            * NVars columns - independent variables
+                            * last column - dependent variable
+            NPoints     -   training set size, NPoints>NVars+1
+            NVars       -   number of independent variables
+
+        OUTPUT PARAMETERS:
+            Info        -   return code:
+                            * -255, in case of unknown internal error
+                            * -4, if internal SVD subroutine haven't converged
+                            * -1, if incorrect parameters was passed (NPoints<NVars+2, NVars<1).
+                            *  1, if subroutine successfully finished
+            LM          -   linear model in the ALGLIB format. Use subroutines of
+                            this unit to work with the model.
+            AR          -   additional results
+
+
+          -- ALGLIB --
+             Copyright 02.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrbuild(ref double[,] xy,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref linearmodel lm,
+            ref lrreport ar)
+        {
+            double[] s = new double[0];
+            int i = 0;
+            double sigma2 = 0;
+            int i_ = 0;
+
+            if( npoints<=nvars+1 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            s = new double[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                s[i] = 1;
+            }
+            lrbuilds(ref xy, ref s, npoints, nvars, ref info, ref lm, ref ar);
+            if( info<0 )
+            {
+                return;
+            }
+            sigma2 = AP.Math.Sqr(ar.rmserror)*npoints/(npoints-nvars-1);
+            for(i=0; i<=nvars; i++)
+            {
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[i,i_] = sigma2*ar.c[i,i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Linear regression
+
+        Variant of LRBuild which uses vector of standatd deviations (errors in
+        function values).
+
+        INPUT PARAMETERS:
+            XY          -   training set, array [0..NPoints-1,0..NVars]:
+                            * NVars columns - independent variables
+                            * last column - dependent variable
+            S           -   standard deviations (errors in function values)
+                            array[0..NPoints-1], S[i]>0.
+            NPoints     -   training set size, NPoints>NVars+1
+            NVars       -   number of independent variables
+
+        OUTPUT PARAMETERS:
+            Info        -   return code:
+                            * -255, in case of unknown internal error
+                            * -4, if internal SVD subroutine haven't converged
+                            * -1, if incorrect parameters was passed (NPoints<NVars+2, NVars<1).
+                            * -2, if S[I]<=0
+                            *  1, if subroutine successfully finished
+            LM          -   linear model in the ALGLIB format. Use subroutines of
+                            this unit to work with the model.
+            AR          -   additional results
+
+
+          -- ALGLIB --
+             Copyright 02.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrbuilds(ref double[,] xy,
+            ref double[] s,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref linearmodel lm,
+            ref lrreport ar)
+        {
+            double[,] xyi = new double[0,0];
+            double[] x = new double[0];
+            double[] means = new double[0];
+            double[] sigmas = new double[0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            int offs = 0;
+            double mean = 0;
+            double variance = 0;
+            double skewness = 0;
+            double kurtosis = 0;
+            int i_ = 0;
+
+            
+            //
+            // Test parameters
+            //
+            if( npoints<=nvars+1 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            
+            //
+            // Copy data, add one more column (constant term)
+            //
+            xyi = new double[npoints-1+1, nvars+1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    xyi[i,i_] = xy[i,i_];
+                }
+                xyi[i,nvars] = 1;
+                xyi[i,nvars+1] = xy[i,nvars];
+            }
+            
+            //
+            // Standartization
+            //
+            x = new double[npoints-1+1];
+            means = new double[nvars-1+1];
+            sigmas = new double[nvars-1+1];
+            for(j=0; j<=nvars-1; j++)
+            {
+                for(i_=0; i_<=npoints-1;i_++)
+                {
+                    x[i_] = xy[i_,j];
+                }
+                descriptivestatistics.calculatemoments(ref x, npoints, ref mean, ref variance, ref skewness, ref kurtosis);
+                means[j] = mean;
+                sigmas[j] = Math.Sqrt(variance);
+                if( (double)(sigmas[j])==(double)(0) )
+                {
+                    sigmas[j] = 1;
+                }
+                for(i=0; i<=npoints-1; i++)
+                {
+                    xyi[i,j] = (xyi[i,j]-means[j])/sigmas[j];
+                }
+            }
+            
+            //
+            // Internal processing
+            //
+            lrinternal(ref xyi, ref s, npoints, nvars+1, ref info, ref lm, ref ar);
+            if( info<0 )
+            {
+                return;
+            }
+            
+            //
+            // Un-standartization
+            //
+            offs = (int)Math.Round(lm.w[3]);
+            for(j=0; j<=nvars-1; j++)
+            {
+                
+                //
+                // Constant term is updated (and its covariance too,
+                // since it gets some variance from J-th component)
+                //
+                lm.w[offs+nvars] = lm.w[offs+nvars]-lm.w[offs+j]*means[j]/sigmas[j];
+                v = means[j]/sigmas[j];
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[nvars,i_] = ar.c[nvars,i_] - v*ar.c[j,i_];
+                }
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[i_,nvars] = ar.c[i_,nvars] - v*ar.c[i_,j];
+                }
+                
+                //
+                // J-th term is updated
+                //
+                lm.w[offs+j] = lm.w[offs+j]/sigmas[j];
+                v = 1/sigmas[j];
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[j,i_] = v*ar.c[j,i_];
+                }
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[i_,j] = v*ar.c[i_,j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Like LRBuildS, but builds model
+
+            Y = A(0)*X[0] + ... + A(N-1)*X[N-1]
+
+        i.e. with zero constant term.
+
+          -- ALGLIB --
+             Copyright 30.10.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrbuildzs(ref double[,] xy,
+            ref double[] s,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref linearmodel lm,
+            ref lrreport ar)
+        {
+            double[,] xyi = new double[0,0];
+            double[] x = new double[0];
+            double[] c = new double[0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            int offs = 0;
+            double mean = 0;
+            double variance = 0;
+            double skewness = 0;
+            double kurtosis = 0;
+            int i_ = 0;
+
+            
+            //
+            // Test parameters
+            //
+            if( npoints<=nvars+1 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            
+            //
+            // Copy data, add one more column (constant term)
+            //
+            xyi = new double[npoints-1+1, nvars+1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    xyi[i,i_] = xy[i,i_];
+                }
+                xyi[i,nvars] = 0;
+                xyi[i,nvars+1] = xy[i,nvars];
+            }
+            
+            //
+            // Standartization: unusual scaling
+            //
+            x = new double[npoints-1+1];
+            c = new double[nvars-1+1];
+            for(j=0; j<=nvars-1; j++)
+            {
+                for(i_=0; i_<=npoints-1;i_++)
+                {
+                    x[i_] = xy[i_,j];
+                }
+                descriptivestatistics.calculatemoments(ref x, npoints, ref mean, ref variance, ref skewness, ref kurtosis);
+                if( (double)(Math.Abs(mean))>(double)(Math.Sqrt(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( (double)(variance)==(double)(0) )
+                    {
+                        variance = 1;
+                    }
+                    c[j] = Math.Sqrt(variance);
+                }
+                for(i=0; i<=npoints-1; i++)
+                {
+                    xyi[i,j] = xyi[i,j]/c[j];
+                }
+            }
+            
+            //
+            // Internal processing
+            //
+            lrinternal(ref xyi, ref s, npoints, nvars+1, ref info, ref lm, ref ar);
+            if( info<0 )
+            {
+                return;
+            }
+            
+            //
+            // Un-standartization
+            //
+            offs = (int)Math.Round(lm.w[3]);
+            for(j=0; j<=nvars-1; j++)
+            {
+                
+                //
+                // J-th term is updated
+                //
+                lm.w[offs+j] = lm.w[offs+j]/c[j];
+                v = 1/c[j];
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[j,i_] = v*ar.c[j,i_];
+                }
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[i_,j] = v*ar.c[i_,j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Like LRBuild but builds model
+
+            Y = A(0)*X[0] + ... + A(N-1)*X[N-1]
+
+        i.e. with zero constant term.
+
+          -- ALGLIB --
+             Copyright 30.10.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrbuildz(ref double[,] xy,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref linearmodel lm,
+            ref lrreport ar)
+        {
+            double[] s = new double[0];
+            int i = 0;
+            double sigma2 = 0;
+            int i_ = 0;
+
+            if( npoints<=nvars+1 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            s = new double[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                s[i] = 1;
+            }
+            lrbuildzs(ref xy, ref s, npoints, nvars, ref info, ref lm, ref ar);
+            if( info<0 )
+            {
+                return;
+            }
+            sigma2 = AP.Math.Sqr(ar.rmserror)*npoints/(npoints-nvars-1);
+            for(i=0; i<=nvars; i++)
+            {
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    ar.c[i,i_] = sigma2*ar.c[i,i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacks coefficients of linear model.
+
+        INPUT PARAMETERS:
+            LM          -   linear model in ALGLIB format
+
+        OUTPUT PARAMETERS:
+            V           -   coefficients, array[0..NVars]
+            NVars       -   number of independent variables (one less than number
+                            of coefficients)
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrunpack(ref linearmodel lm,
+            ref double[] v,
+            ref int nvars)
+        {
+            int offs = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==lrvnum, "LINREG: Incorrect LINREG version!");
+            nvars = (int)Math.Round(lm.w[2]);
+            offs = (int)Math.Round(lm.w[3]);
+            v = new double[nvars+1];
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=nvars;i_++)
+            {
+                v[i_] = lm.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.
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrpack(ref double[] v,
+            int nvars,
+            ref linearmodel lm)
+        {
+            int offs = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            lm.w = new double[4+nvars+1];
+            offs = 4;
+            lm.w[0] = 4+nvars+1;
+            lm.w[1] = lrvnum;
+            lm.w[2] = nvars;
+            lm.w[3] = offs;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+nvars;i_++)
+            {
+                lm.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
+
+          -- ALGLIB --
+             Copyright 03.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double lrprocess(ref linearmodel lm,
+            ref double[] x)
+        {
+            double result = 0;
+            double v = 0;
+            int offs = 0;
+            int nvars = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==lrvnum, "LINREG: Incorrect LINREG version!");
+            nvars = (int)Math.Round(lm.w[2]);
+            offs = (int)Math.Round(lm.w[3]);
+            i1_ = (offs)-(0);
+            v = 0.0;
+            for(i_=0; i_<=nvars-1;i_++)
+            {
+                v += x[i_]*lm.w[i_+i1_];
+            }
+            result = v+lm.w[offs+nvars];
+            return result;
+        }
+
+
+        /*************************************************************************
+        RMS error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   linear model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            root mean square error.
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double lrrmserror(ref linearmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int i = 0;
+            double v = 0;
+            int offs = 0;
+            int nvars = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==lrvnum, "LINREG: Incorrect LINREG version!");
+            nvars = (int)Math.Round(lm.w[2]);
+            offs = (int)Math.Round(lm.w[3]);
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                i1_ = (offs)-(0);
+                v = 0.0;
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    v += xy[i,i_]*lm.w[i_+i1_];
+                }
+                v = v+lm.w[offs+nvars];
+                result = result+AP.Math.Sqr(v-xy[i,nvars]);
+            }
+            result = Math.Sqrt(result/npoints);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   linear model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            average error.
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double lravgerror(ref linearmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int i = 0;
+            double v = 0;
+            int offs = 0;
+            int nvars = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==lrvnum, "LINREG: Incorrect LINREG version!");
+            nvars = (int)Math.Round(lm.w[2]);
+            offs = (int)Math.Round(lm.w[3]);
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                i1_ = (offs)-(0);
+                v = 0.0;
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    v += xy[i,i_]*lm.w[i_+i1_];
+                }
+                v = v+lm.w[offs+nvars];
+                result = result+Math.Abs(v-xy[i,nvars]);
+            }
+            result = result/npoints;
+            return result;
+        }
+
+
+        /*************************************************************************
+        RMS error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   linear model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            average relative error.
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double lravgrelerror(ref linearmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int i = 0;
+            int k = 0;
+            double v = 0;
+            int offs = 0;
+            int nvars = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==lrvnum, "LINREG: Incorrect LINREG version!");
+            nvars = (int)Math.Round(lm.w[2]);
+            offs = (int)Math.Round(lm.w[3]);
+            result = 0;
+            k = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( (double)(xy[i,nvars])!=(double)(0) )
+                {
+                    i1_ = (offs)-(0);
+                    v = 0.0;
+                    for(i_=0; i_<=nvars-1;i_++)
+                    {
+                        v += xy[i,i_]*lm.w[i_+i1_];
+                    }
+                    v = v+lm.w[offs+nvars];
+                    result = result+Math.Abs((v-xy[i,nvars])/xy[i,nvars]);
+                    k = k+1;
+                }
+            }
+            if( k!=0 )
+            {
+                result = result/k;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Copying of LinearModel strucure
+
+        INPUT PARAMETERS:
+            LM1 -   original
+
+        OUTPUT PARAMETERS:
+            LM2 -   copy
+
+          -- ALGLIB --
+             Copyright 15.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrcopy(ref linearmodel lm1,
+            ref linearmodel lm2)
+        {
+            int k = 0;
+            int i_ = 0;
+
+            k = (int)Math.Round(lm1.w[0]);
+            lm2.w = new double[k-1+1];
+            for(i_=0; i_<=k-1;i_++)
+            {
+                lm2.w[i_] = lm1.w[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of LinearModel strucure
+
+        INPUT PARAMETERS:
+            LM      -   original
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which stores model,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 15.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrserialize(ref linearmodel lm,
+            ref double[] ra,
+            ref int rlen)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            rlen = (int)Math.Round(lm.w[0])+1;
+            ra = new double[rlen-1+1];
+            ra[0] = lrvnum;
+            i1_ = (0) - (1);
+            for(i_=1; i_<=rlen-1;i_++)
+            {
+                ra[i_] = lm.w[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Unserialization of DecisionForest strucure
+
+        INPUT PARAMETERS:
+            RA      -   real array which stores decision forest
+
+        OUTPUT PARAMETERS:
+            LM      -   unserialized structure
+
+          -- ALGLIB --
+             Copyright 15.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lrunserialize(ref double[] ra,
+            ref linearmodel lm)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[0])==lrvnum, "LRUnserialize: incorrect array!");
+            lm.w = new double[(int)Math.Round(ra[1])-1+1];
+            i1_ = (1) - (0);
+            for(i_=0; i_<=(int)Math.Round(ra[1])-1;i_++)
+            {
+                lm.w[i_] = ra[i_+i1_];
+            }
+        }
+
+
+        public static void lrlines(ref double[,] xy,
+            ref double[] s,
+            int n,
+            ref int info,
+            ref double a,
+            ref double b,
+            ref double vara,
+            ref double varb,
+            ref double covab,
+            ref double corrab,
+            ref double p)
+        {
+            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;
+
+            if( n<2 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(s[i])<=(double)(0) )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Calculate S, SX, SY, SXX
+            //
+            ss = 0;
+            sx = 0;
+            sy = 0;
+            sxx = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                t = AP.Math.Sqr(s[i]);
+                ss = ss+1/t;
+                sx = sx+xy[i,0]/t;
+                sy = sy+xy[i,1]/t;
+                sxx = sxx+AP.Math.Sqr(xy[i,0])/t;
+            }
+            
+            //
+            // Test for condition number
+            //
+            t = Math.Sqrt(4*AP.Math.Sqr(sx)+AP.Math.Sqr(ss-sxx));
+            e1 = 0.5*(ss+sxx+t);
+            e2 = 0.5*(ss+sxx-t);
+            if( (double)(Math.Min(e1, e2))<=(double)(1000*AP.Math.MachineEpsilon*Math.Max(e1, e2)) )
+            {
+                info = -3;
+                return;
+            }
+            
+            //
+            // Calculate A, B
+            //
+            a = 0;
+            b = 0;
+            stt = 0;
+            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+AP.Math.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+AP.Math.Sqr((xy[i,1]-a-b*xy[i,0])/s[i]);
+                }
+                p = igammaf.incompletegammac(((double)(n-2))/(double)(2), chi2/2);
+            }
+            else
+            {
+                p = 1;
+            }
+            
+            //
+            // Calculate other parameters
+            //
+            vara = (1+AP.Math.Sqr(sx)/(ss*stt))/ss;
+            varb = 1/stt;
+            covab = -(sx/(ss*stt));
+            corrab = covab/Math.Sqrt(vara*varb);
+        }
+
+
+        public static void lrline(ref double[,] xy,
+            int n,
+            ref int info,
+            ref double a,
+            ref double b)
+        {
+            double[] s = new double[0];
+            int i = 0;
+            double vara = 0;
+            double varb = 0;
+            double covab = 0;
+            double corrab = 0;
+            double p = 0;
+
+            if( n<2 )
+            {
+                info = -1;
+                return;
+            }
+            s = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                s[i] = 1;
+            }
+            lrlines(ref xy, ref s, n, ref info, ref a, ref b, ref vara, ref varb, ref covab, ref corrab, ref p);
+        }
+
+
+        /*************************************************************************
+        Internal linear regression subroutine
+        *************************************************************************/
+        private static void lrinternal(ref double[,] xy,
+            ref double[] s,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref linearmodel lm,
+            ref lrreport ar)
+        {
+            double[,] a = new double[0,0];
+            double[,] u = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[,] vm = new double[0,0];
+            double[,] xym = new double[0,0];
+            double[] b = new double[0];
+            double[] sv = new double[0];
+            double[] t = new double[0];
+            double[] svi = new double[0];
+            double[] work = new double[0];
+            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;
+            lrreport ar2 = new lrreport();
+            int offs = 0;
+            linearmodel tlm = new linearmodel();
+            int i_ = 0;
+            int i1_ = 0;
+
+            epstol = 1000;
+            
+            //
+            // Check for errors in data
+            //
+            if( npoints<nvars | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( (double)(s[i])<=(double)(0) )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Create design matrix
+            //
+            a = new double[npoints-1+1, nvars-1+1];
+            b = new double[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                r = 1/s[i];
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    a[i,i_] = r*xy[i,i_];
+                }
+                b[i] = xy[i,nvars]/s[i];
+            }
+            
+            //
+            // Allocate W:
+            // W[0]     array size
+            // W[1]     version number, 0
+            // W[2]     NVars (minus 1, to be compatible with external representation)
+            // W[3]     coefficients offset
+            //
+            lm.w = new double[4+nvars-1+1];
+            offs = 4;
+            lm.w[0] = 4+nvars;
+            lm.w[1] = lrvnum;
+            lm.w[2] = nvars-1;
+            lm.w[3] = offs;
+            
+            //
+            // Solve problem using SVD:
+            //
+            // 0. check for degeneracy (different types)
+            // 1. A = U*diag(sv)*V'
+            // 2. T = b'*U
+            // 3. w = SUM((T[i]/sv[i])*V[..,i])
+            // 4. cov(wi,wj) = SUM(Vji*Vjk/sv[i]^2,K=1..M)
+            //
+            // see $15.4 of "Numerical Recipes in C" for more information
+            //
+            t = new double[nvars-1+1];
+            svi = new double[nvars-1+1];
+            ar.c = new double[nvars-1+1, nvars-1+1];
+            vm = new double[nvars-1+1, nvars-1+1];
+            if( !svd.rmatrixsvd(a, npoints, nvars, 1, 1, 2, ref sv, ref u, ref vt) )
+            {
+                info = -4;
+                return;
+            }
+            if( (double)(sv[0])<=(double)(0) )
+            {
+                
+                //
+                // Degenerate case: zero design matrix.
+                //
+                for(i=offs; i<=offs+nvars-1; i++)
+                {
+                    lm.w[i] = 0;
+                }
+                ar.rmserror = lrrmserror(ref lm, ref xy, npoints);
+                ar.avgerror = lravgerror(ref lm, ref xy, npoints);
+                ar.avgrelerror = lravgrelerror(ref lm, ref xy, npoints);
+                ar.cvrmserror = ar.rmserror;
+                ar.cvavgerror = ar.avgerror;
+                ar.cvavgrelerror = ar.avgrelerror;
+                ar.ncvdefects = 0;
+                ar.cvdefects = new int[nvars-1+1];
+                ar.c = new double[nvars-1+1, nvars-1+1];
+                for(i=0; i<=nvars-1; i++)
+                {
+                    for(j=0; j<=nvars-1; j++)
+                    {
+                        ar.c[i,j] = 0;
+                    }
+                }
+                return;
+            }
+            if( (double)(sv[nvars-1])<=(double)(epstol*AP.Math.MachineEpsilon*sv[0]) )
+            {
+                
+                //
+                // Degenerate case, non-zero design matrix.
+                //
+                // We can leave it and solve task in SVD least squares fashion.
+                // Solution and covariance matrix will be obtained correctly,
+                // but CV error estimates - will not. It is better to reduce
+                // it to non-degenerate task and to obtain correct CV estimates.
+                //
+                for(k=nvars; k>=1; k--)
+                {
+                    if( (double)(sv[k-1])>(double)(epstol*AP.Math.MachineEpsilon*sv[0]) )
+                    {
+                        
+                        //
+                        // Reduce
+                        //
+                        xym = new double[npoints-1+1, k+1];
+                        for(i=0; i<=npoints-1; i++)
+                        {
+                            for(j=0; j<=k-1; j++)
+                            {
+                                r = 0.0;
+                                for(i_=0; i_<=nvars-1;i_++)
+                                {
+                                    r += xy[i,i_]*vt[j,i_];
+                                }
+                                xym[i,j] = r;
+                            }
+                            xym[i,k] = xy[i,nvars];
+                        }
+                        
+                        //
+                        // Solve
+                        //
+                        lrinternal(ref xym, ref s, npoints, k, ref info, ref tlm, ref ar2);
+                        if( info!=1 )
+                        {
+                            return;
+                        }
+                        
+                        //
+                        // Convert back to un-reduced format
+                        //
+                        for(j=0; j<=nvars-1; j++)
+                        {
+                            lm.w[offs+j] = 0;
+                        }
+                        for(j=0; j<=k-1; j++)
+                        {
+                            r = tlm.w[offs+j];
+                            i1_ = (0) - (offs);
+                            for(i_=offs; i_<=offs+nvars-1;i_++)
+                            {
+                                lm.w[i_] = lm.w[i_] + r*vt[j,i_+i1_];
+                            }
+                        }
+                        ar.rmserror = ar2.rmserror;
+                        ar.avgerror = ar2.avgerror;
+                        ar.avgrelerror = ar2.avgrelerror;
+                        ar.cvrmserror = ar2.cvrmserror;
+                        ar.cvavgerror = ar2.cvavgerror;
+                        ar.cvavgrelerror = ar2.cvavgrelerror;
+                        ar.ncvdefects = ar2.ncvdefects;
+                        ar.cvdefects = new int[nvars-1+1];
+                        for(j=0; j<=ar.ncvdefects-1; j++)
+                        {
+                            ar.cvdefects[j] = ar2.cvdefects[j];
+                        }
+                        ar.c = new double[nvars-1+1, nvars-1+1];
+                        work = new double[nvars+1];
+                        blas.matrixmatrixmultiply(ref ar2.c, 0, k-1, 0, k-1, false, ref vt, 0, k-1, 0, nvars-1, false, 1.0, ref vm, 0, k-1, 0, nvars-1, 0.0, ref work);
+                        blas.matrixmatrixmultiply(ref vt, 0, k-1, 0, nvars-1, true, ref vm, 0, k-1, 0, nvars-1, false, 1.0, ref ar.c, 0, nvars-1, 0, nvars-1, 0.0, ref work);
+                        return;
+                    }
+                }
+                info = -255;
+                return;
+            }
+            for(i=0; i<=nvars-1; i++)
+            {
+                if( (double)(sv[i])>(double)(epstol*AP.Math.MachineEpsilon*sv[0]) )
+                {
+                    svi[i] = 1/sv[i];
+                }
+                else
+                {
+                    svi[i] = 0;
+                }
+            }
+            for(i=0; i<=nvars-1; i++)
+            {
+                t[i] = 0;
+            }
+            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.w[offs+i] = 0;
+            }
+            for(i=0; i<=nvars-1; i++)
+            {
+                r = t[i]*svi[i];
+                i1_ = (0) - (offs);
+                for(i_=offs; i_<=offs+nvars-1;i_++)
+                {
+                    lm.w[i_] = lm.w[i_] + r*vt[i,i_+i1_];
+                }
+            }
+            for(j=0; j<=nvars-1; j++)
+            {
+                r = svi[j];
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    vm[i_,j] = r*vt[j,i_];
+                }
+            }
+            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.c[i,j] = r;
+                    ar.c[j,i] = r;
+                }
+            }
+            
+            //
+            // Leave-1-out cross-validation error.
+            //
+            // NOTATIONS:
+            // A            design matrix
+            // A*x = b      original linear least squares task
+            // U*S*V'       SVD of A
+            // ai           i-th row of the A
+            // bi           i-th element of the b
+            // xf           solution of the original LLS task
+            //
+            // Cross-validation error of i-th element from a sample is
+            // calculated using following formula:
+            //
+            //     ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui')     (1)
+            //
+            // This formula can be derived from normal equations of the
+            // original task
+            //
+            //     (A'*A)x = A'*b                                    (2)
+            //
+            // by applying modification (zeroing out i-th row of A) to (2):
+            //
+            //     (A-ai)'*(A-ai) = (A-ai)'*b
+            //
+            // and using Sherman-Morrison formula for updating matrix inverse
+            //
+            // NOTE 1: b is not zeroed out since it is much simpler and
+            // does not influence final result.
+            //
+            // NOTE 2: some design matrices A have such ui that 1-ui*ui'=0.
+            // Formula (1) can't be applied for such cases and they are skipped
+            // from CV calculation (which distorts resulting CV estimate).
+            // But from the properties of U we can conclude that there can
+            // be no more than NVars such vectors. Usually
+            // NVars << NPoints, so in a normal case it only slightly
+            // influences result.
+            //
+            ncv = 0;
+            na = 0;
+            nacv = 0;
+            ar.rmserror = 0;
+            ar.avgerror = 0;
+            ar.avgrelerror = 0;
+            ar.cvrmserror = 0;
+            ar.cvavgerror = 0;
+            ar.cvavgrelerror = 0;
+            ar.ncvdefects = 0;
+            ar.cvdefects = new int[nvars-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                
+                //
+                // Error on a training set
+                //
+                i1_ = (offs)-(0);
+                r = 0.0;
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    r += xy[i,i_]*lm.w[i_+i1_];
+                }
+                ar.rmserror = ar.rmserror+AP.Math.Sqr(r-xy[i,nvars]);
+                ar.avgerror = ar.avgerror+Math.Abs(r-xy[i,nvars]);
+                if( (double)(xy[i,nvars])!=(double)(0) )
+                {
+                    ar.avgrelerror = ar.avgrelerror+Math.Abs((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_];
+                }
+                if( (double)(p)>(double)(1-epstol*AP.Math.MachineEpsilon) )
+                {
+                    ar.cvdefects[ar.ncvdefects] = i;
+                    ar.ncvdefects = ar.ncvdefects+1;
+                    continue;
+                }
+                r = s[i]*(r/s[i]-b[i]*p)/(1-p);
+                ar.cvrmserror = ar.cvrmserror+AP.Math.Sqr(r-xy[i,nvars]);
+                ar.cvavgerror = ar.cvavgerror+Math.Abs(r-xy[i,nvars]);
+                if( (double)(xy[i,nvars])!=(double)(0) )
+                {
+                    ar.cvavgrelerror = ar.cvavgrelerror+Math.Abs((r-xy[i,nvars])/xy[i,nvars]);
+                    nacv = nacv+1;
+                }
+                ncv = ncv+1;
+            }
+            if( ncv==0 )
+            {
+                
+                //
+                // Something strange: ALL ui are degenerate.
+                // Unexpected...
+                //
+                info = -255;
+                return;
+            }
+            ar.rmserror = Math.Sqrt(ar.rmserror/npoints);
+            ar.avgerror = ar.avgerror/npoints;
+            if( na!=0 )
+            {
+                ar.avgrelerror = ar.avgrelerror/na;
+            }
+            ar.cvrmserror = Math.Sqrt(ar.cvrmserror/ncv);
+            ar.cvavgerror = ar.cvavgerror/ncv;
+            if( nacv!=0 )
+            {
+                ar.cvavgrelerror = ar.cvavgrelerror/nacv;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/logit.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/logit.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/logit.cs	(revision 2645)
@@ -0,0 +1,1667 @@
+/*************************************************************************
+Copyright (c) 2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class logit
+    {
+        public struct logitmodel
+        {
+            public double[] w;
+        };
+
+
+        public struct logitmcstate
+        {
+            public bool brackt;
+            public bool stage1;
+            public int infoc;
+            public double dg;
+            public double dgm;
+            public double dginit;
+            public double dgtest;
+            public double dgx;
+            public double dgxm;
+            public double dgy;
+            public double dgym;
+            public double finit;
+            public double ftest1;
+            public double fm;
+            public double fx;
+            public double fxm;
+            public double fy;
+            public double fym;
+            public double stx;
+            public double sty;
+            public double stmin;
+            public double stmax;
+            public double width;
+            public double width1;
+            public double xtrapf;
+        };
+
+
+        /*************************************************************************
+        MNLReport structure contains information about training process:
+        * NGrad     -   number of gradient calculations
+        * NHess     -   number of Hessian calculations
+        *************************************************************************/
+        public struct mnlreport
+        {
+            public int ngrad;
+            public int nhess;
+        };
+
+
+
+
+        public const double xtol = 100*AP.Math.MachineEpsilon;
+        public const double ftol = 0.0001;
+        public const double gtol = 0.3;
+        public const int maxfev = 20;
+        public const double stpmin = 1.0E-2;
+        public const double stpmax = 1.0E5;
+        public const int logitvnum = 6;
+
+
+        /*************************************************************************
+        This subroutine trains logit model.
+
+        INPUT PARAMETERS:
+            XY          -   training set, array[0..NPoints-1,0..NVars]
+                            First NVars columns store values of independent
+                            variables, next column stores number of class (from 0
+                            to NClasses-1) which dataset element belongs to. Fractional
+                            values are rounded to nearest integer.
+            NPoints     -   training set size, NPoints>=1
+            NVars       -   number of independent variables, NVars>=1
+            NClasses    -   number of classes, NClasses>=2
+
+        OUTPUT PARAMETERS:
+            Info        -   return code:
+                            * -2, if there is a point with class number
+                                  outside of [0..NClasses-1].
+                            * -1, if incorrect parameters was passed
+                                  (NPoints<NVars+2, NVars<1, NClasses<2).
+                            *  1, if task has been solved
+            LM          -   model built
+            Rep         -   training report
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnltrainh(ref double[,] xy,
+            int npoints,
+            int nvars,
+            int nclasses,
+            ref int info,
+            ref logitmodel lm,
+            ref mnlreport rep)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int m = 0;
+            int n = 0;
+            int ssize = 0;
+            bool allsame = new bool();
+            int offs = 0;
+            double threshold = 0;
+            double wminstep = 0;
+            double decay = 0;
+            int wdim = 0;
+            int expoffs = 0;
+            double v = 0;
+            double s = 0;
+            mlpbase.multilayerperceptron network = new mlpbase.multilayerperceptron();
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double e = 0;
+            double[] g = new double[0];
+            double[,] h = new double[0,0];
+            bool spd = new bool();
+            int cvcnt = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[] wbase = new double[0];
+            double wstep = 0;
+            double[] wdir = new double[0];
+            double[] work = new double[0];
+            int mcstage = 0;
+            logitmcstate mcstate = new logitmcstate();
+            int mcinfo = 0;
+            int mcnfev = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            threshold = 1000*AP.Math.MachineEpsilon;
+            wminstep = 0.001;
+            decay = 0.001;
+            
+            //
+            // Test for inputs
+            //
+            if( npoints<nvars+2 | nvars<1 | nclasses<2 )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( (int)Math.Round(xy[i,nvars])<0 | (int)Math.Round(xy[i,nvars])>=nclasses )
+                {
+                    info = -2;
+                    return;
+                }
+            }
+            info = 1;
+            
+            //
+            // Initialize data
+            //
+            rep.ngrad = 0;
+            rep.nhess = 0;
+            
+            //
+            // Allocate array
+            //
+            wdim = (nvars+1)*(nclasses-1);
+            offs = 5;
+            expoffs = offs+wdim;
+            ssize = 5+(nvars+1)*(nclasses-1)+nclasses;
+            lm.w = new double[ssize-1+1];
+            lm.w[0] = ssize;
+            lm.w[1] = logitvnum;
+            lm.w[2] = nvars;
+            lm.w[3] = nclasses;
+            lm.w[4] = offs;
+            
+            //
+            // Degenerate case: all outputs are equal
+            //
+            allsame = true;
+            for(i=1; i<=npoints-1; i++)
+            {
+                if( (int)Math.Round(xy[i,nvars])!=(int)Math.Round(xy[i-1,nvars]) )
+                {
+                    allsame = false;
+                }
+            }
+            if( allsame )
+            {
+                for(i=0; i<=(nvars+1)*(nclasses-1)-1; i++)
+                {
+                    lm.w[offs+i] = 0;
+                }
+                v = -(2*Math.Log(AP.Math.MinRealNumber));
+                k = (int)Math.Round(xy[0,nvars]);
+                if( k==nclasses-1 )
+                {
+                    for(i=0; i<=nclasses-2; i++)
+                    {
+                        lm.w[offs+i*(nvars+1)+nvars] = -v;
+                    }
+                }
+                else
+                {
+                    for(i=0; i<=nclasses-2; i++)
+                    {
+                        if( i==k )
+                        {
+                            lm.w[offs+i*(nvars+1)+nvars] = +v;
+                        }
+                        else
+                        {
+                            lm.w[offs+i*(nvars+1)+nvars] = 0;
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // General case.
+            // Prepare task and network. Allocate space.
+            //
+            mlpbase.mlpcreatec0(nvars, nclasses, ref network);
+            mlpbase.mlpinitpreprocessor(ref network, ref xy, npoints);
+            mlpbase.mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            for(i=0; i<=wcount-1; i++)
+            {
+                network.weights[i] = (2*AP.Math.RandomReal()-1)/nvars;
+            }
+            g = new double[wcount-1+1];
+            h = new double[wcount-1+1, wcount-1+1];
+            wbase = new double[wcount-1+1];
+            wdir = new double[wcount-1+1];
+            work = new double[wcount-1+1];
+            
+            //
+            // First stage: optimize in gradient direction.
+            //
+            for(k=0; k<=wcount/3+10; k++)
+            {
+                
+                //
+                // Calculate gradient in starting point
+                //
+                mlpbase.mlpgradnbatch(ref network, ref xy, npoints, ref e, ref g);
+                v = 0.0;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    v += network.weights[i_]*network.weights[i_];
+                }
+                e = e+0.5*decay*v;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    g[i_] = g[i_] + decay*network.weights[i_];
+                }
+                rep.ngrad = rep.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_];
+                }
+                wstep = Math.Sqrt(v);
+                v = 1/Math.Sqrt(v);
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    wdir[i_] = v*wdir[i_];
+                }
+                mcstage = 0;
+                mnlmcsrch(wcount, ref network.weights, ref e, ref g, ref wdir, ref wstep, ref mcinfo, ref mcnfev, ref work, ref mcstate, ref mcstage);
+                while( mcstage!=0 )
+                {
+                    mlpbase.mlpgradnbatch(ref network, ref xy, npoints, ref e, ref g);
+                    v = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        v += network.weights[i_]*network.weights[i_];
+                    }
+                    e = e+0.5*decay*v;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        g[i_] = g[i_] + decay*network.weights[i_];
+                    }
+                    rep.ngrad = rep.ngrad+1;
+                    mnlmcsrch(wcount, ref network.weights, ref e, ref g, ref wdir, ref wstep, ref mcinfo, ref mcnfev, ref work, ref mcstate, ref mcstage);
+                }
+            }
+            
+            //
+            // Second stage: use Hessian when we are close to the minimum
+            //
+            while( true )
+            {
+                
+                //
+                // Calculate and update E/G/H
+                //
+                mlpbase.mlphessiannbatch(ref network, ref xy, npoints, ref e, ref g, ref h);
+                v = 0.0;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    v += network.weights[i_]*network.weights[i_];
+                }
+                e = e+0.5*decay*v;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    g[i_] = g[i_] + decay*network.weights[i_];
+                }
+                for(k=0; k<=wcount-1; k++)
+                {
+                    h[k,k] = h[k,k]+decay;
+                }
+                rep.nhess = rep.nhess+1;
+                
+                //
+                // Select step direction
+                // NOTE: it is important to use lower-triangle Cholesky
+                // factorization since it is much faster than higher-triangle version.
+                //
+                spd = cholesky.spdmatrixcholesky(ref h, wcount, false);
+                if( spd )
+                {
+                    spd = spdsolve.spdmatrixcholeskysolve(ref h, g, wcount, false, ref wdir);
+                }
+                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_];
+                }
+                wstep = Math.Sqrt(v);
+                v = 1/Math.Sqrt(v);
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    wdir[i_] = v*wdir[i_];
+                }
+                mcstage = 0;
+                mnlmcsrch(wcount, ref network.weights, ref e, ref g, ref wdir, ref wstep, ref mcinfo, ref mcnfev, ref work, ref mcstate, ref mcstage);
+                while( mcstage!=0 )
+                {
+                    mlpbase.mlpgradnbatch(ref network, ref xy, npoints, ref e, ref g);
+                    v = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        v += network.weights[i_]*network.weights[i_];
+                    }
+                    e = e+0.5*decay*v;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        g[i_] = g[i_] + decay*network.weights[i_];
+                    }
+                    rep.ngrad = rep.ngrad+1;
+                    mnlmcsrch(wcount, ref network.weights, ref e, ref g, ref wdir, ref wstep, ref mcinfo, ref mcnfev, ref work, ref mcstate, ref mcstage);
+                }
+                if( spd & (mcinfo==2 | mcinfo==4 | mcinfo==6) )
+                {
+                    break;
+                }
+            }
+            
+            //
+            // Convert from NN format to MNL format
+            //
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+wcount-1;i_++)
+            {
+                lm.w[i_] = network.weights[i_+i1_];
+            }
+            for(k=0; k<=nvars-1; k++)
+            {
+                for(i=0; i<=nclasses-2; i++)
+                {
+                    s = network.columnsigmas[k];
+                    if( (double)(s)==(double)(0) )
+                    {
+                        s = 1;
+                    }
+                    j = offs+(nvars+1)*i;
+                    v = lm.w[j+k];
+                    lm.w[j+k] = v/s;
+                    lm.w[j+nvars] = lm.w[j+nvars]+v*network.columnmeans[k]/s;
+                }
+            }
+            for(k=0; k<=nclasses-2; k++)
+            {
+                lm.w[offs+(nvars+1)*k+nvars] = -lm.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].
+
+        OUTPUT PARAMETERS:
+            Y       -   result, array[0..NClasses-1]
+                        Vector of posterior probabilities for classification task.
+                        Subroutine does not allocate memory for this vector, it is
+                        responsibility of a caller to allocate it. Array  must  be
+                        at least [0..NClasses-1].
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnlprocess(ref logitmodel lm,
+            ref double[] x,
+            ref double[] y)
+        {
+            int nvars = 0;
+            int nclasses = 0;
+            int offs = 0;
+            int i = 0;
+            int i1 = 0;
+            double v = 0;
+            double mx = 0;
+            double s = 0;
+
+            System.Diagnostics.Debug.Assert((double)(lm.w[1])==(double)(logitvnum), "MNLProcess: unexpected model version");
+            nvars = (int)Math.Round(lm.w[2]);
+            nclasses = (int)Math.Round(lm.w[3]);
+            offs = (int)Math.Round(lm.w[4]);
+            mnliexp(ref lm.w, ref x);
+            s = 0;
+            i1 = offs+(nvars+1)*(nclasses-1);
+            for(i=i1; i<=i1+nclasses-1; i++)
+            {
+                s = s+lm.w[i];
+            }
+            for(i=0; i<=nclasses-1; i++)
+            {
+                y[i] = lm.w[i1+i]/s;
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacks coefficients of logit model. Logit model have form:
+
+            P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1))
+                  S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when i<M-1
+                S(M-1) = 1
+
+        INPUT PARAMETERS:
+            LM          -   logit model in ALGLIB format
+
+        OUTPUT PARAMETERS:
+            V           -   coefficients, array[0..NClasses-2,0..NVars]
+            NVars       -   number of independent variables
+            NClasses    -   number of classes
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnlunpack(ref logitmodel lm,
+            ref double[,] a,
+            ref int nvars,
+            ref int nclasses)
+        {
+            int offs = 0;
+            int i = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((double)(lm.w[1])==(double)(logitvnum), "MNLUnpack: unexpected model version");
+            nvars = (int)Math.Round(lm.w[2]);
+            nclasses = (int)Math.Round(lm.w[3]);
+            offs = (int)Math.Round(lm.w[4]);
+            a = new double[nclasses-2+1, nvars+1];
+            for(i=0; i<=nclasses-2; i++)
+            {
+                i1_ = (offs+i*(nvars+1)) - (0);
+                for(i_=0; i_<=nvars;i_++)
+                {
+                    a[i,i_] = lm.w[i_+i1_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        "Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack
+        reversed).
+
+        INPUT PARAMETERS:
+            A           -   model (see MNLUnpack)
+            NVars       -   number of independent variables
+            NClasses    -   number of classes
+
+        OUTPUT PARAMETERS:
+            LM          -   logit model.
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnlpack(ref double[,] a,
+            int nvars,
+            int nclasses,
+            ref logitmodel lm)
+        {
+            int offs = 0;
+            int i = 0;
+            int wdim = 0;
+            int ssize = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            wdim = (nvars+1)*(nclasses-1);
+            offs = 5;
+            ssize = 5+(nvars+1)*(nclasses-1)+nclasses;
+            lm.w = new double[ssize-1+1];
+            lm.w[0] = ssize;
+            lm.w[1] = logitvnum;
+            lm.w[2] = nvars;
+            lm.w[3] = nclasses;
+            lm.w[4] = offs;
+            for(i=0; i<=nclasses-2; i++)
+            {
+                i1_ = (0) - (offs+i*(nvars+1));
+                for(i_=offs+i*(nvars+1); i_<=offs+i*(nvars+1)+nvars;i_++)
+                {
+                    lm.w[i_] = a[i,i_+i1_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Copying of LogitModel strucure
+
+        INPUT PARAMETERS:
+            LM1 -   original
+
+        OUTPUT PARAMETERS:
+            LM2 -   copy
+
+          -- ALGLIB --
+             Copyright 15.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnlcopy(ref logitmodel lm1,
+            ref logitmodel lm2)
+        {
+            int k = 0;
+            int i_ = 0;
+
+            k = (int)Math.Round(lm1.w[0]);
+            lm2.w = new double[k-1+1];
+            for(i_=0; i_<=k-1;i_++)
+            {
+                lm2.w[i_] = lm1.w[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of LogitModel strucure
+
+        INPUT PARAMETERS:
+            LM      -   original
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which stores model,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 15.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnlserialize(ref logitmodel lm,
+            ref double[] ra,
+            ref int rlen)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            rlen = (int)Math.Round(lm.w[0])+1;
+            ra = new double[rlen-1+1];
+            ra[0] = logitvnum;
+            i1_ = (0) - (1);
+            for(i_=1; i_<=rlen-1;i_++)
+            {
+                ra[i_] = lm.w[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Unserialization of LogitModel strucure
+
+        INPUT PARAMETERS:
+            RA      -   real array which stores model
+
+        OUTPUT PARAMETERS:
+            LM      -   restored model
+
+          -- ALGLIB --
+             Copyright 15.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mnlunserialize(ref double[] ra,
+            ref logitmodel lm)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[0])==logitvnum, "MNLUnserialize: incorrect array!");
+            lm.w = new double[(int)Math.Round(ra[1])-1+1];
+            i1_ = (1) - (0);
+            for(i_=0; i_<=(int)Math.Round(ra[1])-1;i_++)
+            {
+                lm.w[i_] = ra[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Average cross-entropy (in bits per element) on the test set
+
+        INPUT PARAMETERS:
+            LM      -   logit model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            CrossEntropy/(NPoints*ln(2)).
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mnlavgce(ref logitmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int nvars = 0;
+            int nclasses = 0;
+            int i = 0;
+            int j = 0;
+            double[] workx = new double[0];
+            double[] worky = new double[0];
+            int nmax = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert((double)(lm.w[1])==(double)(logitvnum), "MNLClsError: unexpected model version");
+            nvars = (int)Math.Round(lm.w[2]);
+            nclasses = (int)Math.Round(lm.w[3]);
+            workx = new double[nvars-1+1];
+            worky = new double[nclasses-1+1];
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                System.Diagnostics.Debug.Assert((int)Math.Round(xy[i,nvars])>=0 & (int)Math.Round(xy[i,nvars])<nclasses, "MNLAvgCE: incorrect class number!");
+                
+                //
+                // Process
+                //
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    workx[i_] = xy[i,i_];
+                }
+                mnlprocess(ref lm, ref workx, ref worky);
+                if( (double)(worky[(int)Math.Round(xy[i,nvars])])>(double)(0) )
+                {
+                    result = result-Math.Log(worky[(int)Math.Round(xy[i,nvars])]);
+                }
+                else
+                {
+                    result = result-Math.Log(AP.Math.MinRealNumber);
+                }
+            }
+            result = result/(npoints*Math.Log(2));
+            return result;
+        }
+
+
+        /*************************************************************************
+        Relative classification error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   logit model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            percent of incorrectly classified cases.
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mnlrelclserror(ref logitmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+
+            result = (double)(mnlclserror(ref lm, ref xy, npoints))/(double)(npoints);
+            return result;
+        }
+
+
+        /*************************************************************************
+        RMS error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   logit model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            root mean square error (error when estimating posterior probabilities).
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mnlrmserror(ref logitmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==logitvnum, "MNLRMSError: Incorrect MNL version!");
+            mnlallerrors(ref lm, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = rms;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   logit model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            average error (error when estimating posterior probabilities).
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mnlavgerror(ref logitmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==logitvnum, "MNLRMSError: Incorrect MNL version!");
+            mnlallerrors(ref lm, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = avg;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average relative error on the test set
+
+        INPUT PARAMETERS:
+            LM      -   logit model
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            average relative error (error when estimating posterior probabilities).
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mnlavgrelerror(ref logitmodel lm,
+            ref double[,] xy,
+            int ssize)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==logitvnum, "MNLRMSError: Incorrect MNL version!");
+            mnlallerrors(ref lm, ref xy, ssize, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = avgrel;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Classification error on test set = MNLRelClsError*NPoints
+
+          -- ALGLIB --
+             Copyright 10.09.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static int mnlclserror(ref logitmodel lm,
+            ref double[,] xy,
+            int npoints)
+        {
+            int result = 0;
+            int nvars = 0;
+            int nclasses = 0;
+            int i = 0;
+            int j = 0;
+            double[] workx = new double[0];
+            double[] worky = new double[0];
+            int nmax = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert((double)(lm.w[1])==(double)(logitvnum), "MNLClsError: unexpected model version");
+            nvars = (int)Math.Round(lm.w[2]);
+            nclasses = (int)Math.Round(lm.w[3]);
+            workx = new double[nvars-1+1];
+            worky = new double[nclasses-1+1];
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                
+                //
+                // Process
+                //
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    workx[i_] = xy[i,i_];
+                }
+                mnlprocess(ref lm, ref workx, ref worky);
+                
+                //
+                // Logit version of the answer
+                //
+                nmax = 0;
+                for(j=0; j<=nclasses-1; j++)
+                {
+                    if( (double)(worky[j])>(double)(worky[nmax]) )
+                    {
+                        nmax = j;
+                    }
+                }
+                
+                //
+                // compare
+                //
+                if( nmax!=(int)Math.Round(xy[i,nvars]) )
+                {
+                    result = result+1;
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Places exponents of the anti-overflow shifted
+        internal linear outputs into the service part of the W array.
+        *************************************************************************/
+        private static void mnliexp(ref double[] w,
+            ref double[] x)
+        {
+            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;
+
+            System.Diagnostics.Debug.Assert((double)(w[1])==(double)(logitvnum), "LOGIT: unexpected model version");
+            nvars = (int)Math.Round(w[2]);
+            nclasses = (int)Math.Round(w[3]);
+            offs = (int)Math.Round(w[4]);
+            i1 = offs+(nvars+1)*(nclasses-1);
+            for(i=0; i<=nclasses-2; i++)
+            {
+                i1_ = (0)-(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];
+            }
+            w[i1+nclasses-1] = 0;
+            mx = 0;
+            for(i=i1; i<=i1+nclasses-1; i++)
+            {
+                mx = Math.Max(mx, w[i]);
+            }
+            for(i=i1; i<=i1+nclasses-1; i++)
+            {
+                w[i] = Math.Exp(w[i]-mx);
+            }
+        }
+
+
+        /*************************************************************************
+        Calculation of all types of errors
+
+          -- ALGLIB --
+             Copyright 30.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        private static void mnlallerrors(ref logitmodel lm,
+            ref double[,] xy,
+            int npoints,
+            ref double relcls,
+            ref double avgce,
+            ref double rms,
+            ref double avg,
+            ref double avgrel)
+        {
+            int nvars = 0;
+            int nclasses = 0;
+            int i = 0;
+            double[] buf = new double[0];
+            double[] workx = new double[0];
+            double[] y = new double[0];
+            double[] dy = new double[0];
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(lm.w[1])==logitvnum, "MNL unit: Incorrect MNL version!");
+            nvars = (int)Math.Round(lm.w[2]);
+            nclasses = (int)Math.Round(lm.w[3]);
+            workx = new double[nvars-1+1];
+            y = new double[nclasses-1+1];
+            dy = new double[0+1];
+            bdss.dserrallocate(nclasses, ref buf);
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    workx[i_] = xy[i,i_];
+                }
+                mnlprocess(ref lm, ref workx, ref y);
+                dy[0] = xy[i,nvars];
+                bdss.dserraccumulate(ref buf, ref y, ref dy);
+            }
+            bdss.dserrfinish(ref buf);
+            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
+        *************************************************************************/
+        private static void mnlmcsrch(int n,
+            ref double[] x,
+            ref double f,
+            ref double[] g,
+            ref double[] s,
+            ref double stp,
+            ref int info,
+            ref int nfev,
+            ref double[] wa,
+            ref logitmcstate state,
+            ref int stage)
+        {
+            double v = 0;
+            double p5 = 0;
+            double p66 = 0;
+            double zero = 0;
+            int i_ = 0;
+
+            
+            //
+            // init
+            //
+            p5 = 0.5;
+            p66 = 0.66;
+            state.xtrapf = 4.0;
+            zero = 0;
+            
+            //
+            // Main cycle
+            //
+            while( true )
+            {
+                if( stage==0 )
+                {
+                    
+                    //
+                    // NEXT
+                    //
+                    stage = 2;
+                    continue;
+                }
+                if( stage==2 )
+                {
+                    state.infoc = 1;
+                    info = 0;
+                    
+                    //
+                    //     CHECK THE INPUT PARAMETERS FOR ERRORS.
+                    //
+                    if( n<=0 | (double)(stp)<=(double)(0) | (double)(ftol)<(double)(0) | (double)(gtol)<(double)(zero) | (double)(xtol)<(double)(zero) | (double)(stpmin)<(double)(zero) | (double)(stpmax)<(double)(stpmin) | maxfev<=0 )
+                    {
+                        stage = 0;
+                        return;
+                    }
+                    
+                    //
+                    //     COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION
+                    //     AND CHECK THAT S IS A DESCENT DIRECTION.
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        v += g[i_]*s[i_];
+                    }
+                    state.dginit = v;
+                    if( (double)(state.dginit)>=(double)(0) )
+                    {
+                        stage = 0;
+                        return;
+                    }
+                    
+                    //
+                    //     INITIALIZE LOCAL VARIABLES.
+                    //
+                    state.brackt = false;
+                    state.stage1 = true;
+                    nfev = 0;
+                    state.finit = f;
+                    state.dgtest = ftol*state.dginit;
+                    state.width = stpmax-stpmin;
+                    state.width1 = state.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.stx = 0;
+                    state.fx = state.finit;
+                    state.dgx = state.dginit;
+                    state.sty = 0;
+                    state.fy = state.finit;
+                    state.dgy = state.dginit;
+                    
+                    //
+                    // NEXT
+                    //
+                    stage = 3;
+                    continue;
+                }
+                if( stage==3 )
+                {
+                    
+                    //
+                    //     START OF ITERATION.
+                    //
+                    //     SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND
+                    //     TO THE PRESENT INTERVAL OF UNCERTAINTY.
+                    //
+                    if( state.brackt )
+                    {
+                        if( (double)(state.stx)<(double)(state.sty) )
+                        {
+                            state.stmin = state.stx;
+                            state.stmax = state.sty;
+                        }
+                        else
+                        {
+                            state.stmin = state.sty;
+                            state.stmax = state.stx;
+                        }
+                    }
+                    else
+                    {
+                        state.stmin = state.stx;
+                        state.stmax = stp+state.xtrapf*(stp-state.stx);
+                    }
+                    
+                    //
+                    //        FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN.
+                    //
+                    if( (double)(stp)>(double)(stpmax) )
+                    {
+                        stp = stpmax;
+                    }
+                    if( (double)(stp)<(double)(stpmin) )
+                    {
+                        stp = stpmin;
+                    }
+                    
+                    //
+                    //        IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET
+                    //        STP BE THE LOWEST POINT OBTAINED SO FAR.
+                    //
+                    if( state.brackt & ((double)(stp)<=(double)(state.stmin) | (double)(stp)>=(double)(state.stmax)) | nfev>=maxfev-1 | state.infoc==0 | state.brackt & (double)(state.stmax-state.stmin)<=(double)(xtol*state.stmax) )
+                    {
+                        stp = state.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;
+                }
+                if( stage==4 )
+                {
+                    info = 0;
+                    nfev = nfev+1;
+                    v = 0.0;
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        v += g[i_]*s[i_];
+                    }
+                    state.dg = v;
+                    state.ftest1 = state.finit+stp*state.dgtest;
+                    
+                    //
+                    //        TEST FOR CONVERGENCE.
+                    //
+                    if( state.brackt & ((double)(stp)<=(double)(state.stmin) | (double)(stp)>=(double)(state.stmax)) | state.infoc==0 )
+                    {
+                        info = 6;
+                    }
+                    if( (double)(stp)==(double)(stpmax) & (double)(f)<=(double)(state.ftest1) & (double)(state.dg)<=(double)(state.dgtest) )
+                    {
+                        info = 5;
+                    }
+                    if( (double)(stp)==(double)(stpmin) & ((double)(f)>(double)(state.ftest1) | (double)(state.dg)>=(double)(state.dgtest)) )
+                    {
+                        info = 4;
+                    }
+                    if( nfev>=maxfev )
+                    {
+                        info = 3;
+                    }
+                    if( state.brackt & (double)(state.stmax-state.stmin)<=(double)(xtol*state.stmax) )
+                    {
+                        info = 2;
+                    }
+                    if( (double)(f)<=(double)(state.ftest1) & (double)(Math.Abs(state.dg))<=(double)(-(gtol*state.dginit)) )
+                    {
+                        info = 1;
+                    }
+                    
+                    //
+                    //        CHECK FOR TERMINATION.
+                    //
+                    if( info!=0 )
+                    {
+                        stage = 0;
+                        return;
+                    }
+                    
+                    //
+                    //        IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED
+                    //        FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE.
+                    //
+                    if( state.stage1 & (double)(f)<=(double)(state.ftest1) & (double)(state.dg)>=(double)(Math.Min(ftol, gtol)*state.dginit) )
+                    {
+                        state.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.stage1 & (double)(f)<=(double)(state.fx) & (double)(f)>(double)(state.ftest1) )
+                    {
+                        
+                        //
+                        //           DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES.
+                        //
+                        state.fm = f-stp*state.dgtest;
+                        state.fxm = state.fx-state.stx*state.dgtest;
+                        state.fym = state.fy-state.sty*state.dgtest;
+                        state.dgm = state.dg-state.dgtest;
+                        state.dgxm = state.dgx-state.dgtest;
+                        state.dgym = state.dgy-state.dgtest;
+                        
+                        //
+                        //           CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
+                        //           AND TO COMPUTE THE NEW STEP.
+                        //
+                        mnlmcstep(ref state.stx, ref state.fxm, ref state.dgxm, ref state.sty, ref state.fym, ref state.dgym, ref stp, state.fm, state.dgm, ref state.brackt, state.stmin, state.stmax, ref state.infoc);
+                        
+                        //
+                        //           RESET THE FUNCTION AND GRADIENT VALUES FOR F.
+                        //
+                        state.fx = state.fxm+state.stx*state.dgtest;
+                        state.fy = state.fym+state.sty*state.dgtest;
+                        state.dgx = state.dgxm+state.dgtest;
+                        state.dgy = state.dgym+state.dgtest;
+                    }
+                    else
+                    {
+                        
+                        //
+                        //           CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY
+                        //           AND TO COMPUTE THE NEW STEP.
+                        //
+                        mnlmcstep(ref state.stx, ref state.fx, ref state.dgx, ref state.sty, ref state.fy, ref state.dgy, ref stp, f, state.dg, ref state.brackt, state.stmin, state.stmax, ref state.infoc);
+                    }
+                    
+                    //
+                    //        FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE
+                    //        INTERVAL OF UNCERTAINTY.
+                    //
+                    if( state.brackt )
+                    {
+                        if( (double)(Math.Abs(state.sty-state.stx))>=(double)(p66*state.width1) )
+                        {
+                            stp = state.stx+p5*(state.sty-state.stx);
+                        }
+                        state.width1 = state.width;
+                        state.width = Math.Abs(state.sty-state.stx);
+                    }
+                    
+                    //
+                    //  NEXT.
+                    //
+                    stage = 3;
+                    continue;
+                }
+            }
+        }
+
+
+        private static void mnlmcstep(ref double stx,
+            ref double fx,
+            ref double dx,
+            ref double sty,
+            ref double fy,
+            ref double dy,
+            ref double stp,
+            double fp,
+            double dp,
+            ref bool brackt,
+            double stmin,
+            double stmax,
+            ref int info)
+        {
+            bool bound = new bool();
+            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;
+
+            info = 0;
+            
+            //
+            //     CHECK THE INPUT PARAMETERS FOR ERRORS.
+            //
+            if( brackt & ((double)(stp)<=(double)(Math.Min(stx, sty)) | (double)(stp)>=(double)(Math.Max(stx, sty))) | (double)(dx*(stp-stx))>=(double)(0) | (double)(stmax)<(double)(stmin) )
+            {
+                return;
+            }
+            
+            //
+            //     DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN.
+            //
+            sgnd = dp*(dx/Math.Abs(dx));
+            
+            //
+            //     FIRST CASE. A HIGHER FUNCTION VALUE.
+            //     THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER
+            //     TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN,
+            //     ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN.
+            //
+            if( (double)(fp)>(double)(fx) )
+            {
+                info = 1;
+                bound = true;
+                theta = 3*(fx-fp)/(stp-stx)+dx+dp;
+                s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dx), Math.Abs(dp)));
+                gamma = s*Math.Sqrt(AP.Math.Sqr(theta/s)-dx/s*(dp/s));
+                if( (double)(stp)<(double)(stx) )
+                {
+                    gamma = -gamma;
+                }
+                p = gamma-dx+theta;
+                q = gamma-dx+gamma+dp;
+                r = p/q;
+                stpc = stx+r*(stp-stx);
+                stpq = stx+dx/((fx-fp)/(stp-stx)+dx)/2*(stp-stx);
+                if( (double)(Math.Abs(stpc-stx))<(double)(Math.Abs(stpq-stx)) )
+                {
+                    stpf = stpc;
+                }
+                else
+                {
+                    stpf = stpc+(stpq-stpc)/2;
+                }
+                brackt = true;
+            }
+            else
+            {
+                if( (double)(sgnd)<(double)(0) )
+                {
+                    
+                    //
+                    //     SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF
+                    //     OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC
+                    //     STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP,
+                    //     THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN.
+                    //
+                    info = 2;
+                    bound = false;
+                    theta = 3*(fx-fp)/(stp-stx)+dx+dp;
+                    s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dx), Math.Abs(dp)));
+                    gamma = s*Math.Sqrt(AP.Math.Sqr(theta/s)-dx/s*(dp/s));
+                    if( (double)(stp)>(double)(stx) )
+                    {
+                        gamma = -gamma;
+                    }
+                    p = gamma-dp+theta;
+                    q = gamma-dp+gamma+dx;
+                    r = p/q;
+                    stpc = stp+r*(stx-stp);
+                    stpq = stp+dp/(dp-dx)*(stx-stp);
+                    if( (double)(Math.Abs(stpc-stp))>(double)(Math.Abs(stpq-stp)) )
+                    {
+                        stpf = stpc;
+                    }
+                    else
+                    {
+                        stpf = stpq;
+                    }
+                    brackt = true;
+                }
+                else
+                {
+                    if( (double)(Math.Abs(dp))<(double)(Math.Abs(dx)) )
+                    {
+                        
+                        //
+                        //     THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE
+                        //     SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES.
+                        //     THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY
+                        //     IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC
+                        //     IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE
+                        //     EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO
+                        //     COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP
+                        //     CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN.
+                        //
+                        info = 3;
+                        bound = true;
+                        theta = 3*(fx-fp)/(stp-stx)+dx+dp;
+                        s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dx), Math.Abs(dp)));
+                        
+                        //
+                        //        THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND
+                        //        TO INFINITY IN THE DIRECTION OF THE STEP.
+                        //
+                        gamma = s*Math.Sqrt(Math.Max(0, AP.Math.Sqr(theta/s)-dx/s*(dp/s)));
+                        if( (double)(stp)>(double)(stx) )
+                        {
+                            gamma = -gamma;
+                        }
+                        p = gamma-dp+theta;
+                        q = gamma+(dx-dp)+gamma;
+                        r = p/q;
+                        if( (double)(r)<(double)(0) & (double)(gamma)!=(double)(0) )
+                        {
+                            stpc = stp+r*(stx-stp);
+                        }
+                        else
+                        {
+                            if( (double)(stp)>(double)(stx) )
+                            {
+                                stpc = stmax;
+                            }
+                            else
+                            {
+                                stpc = stmin;
+                            }
+                        }
+                        stpq = stp+dp/(dp-dx)*(stx-stp);
+                        if( brackt )
+                        {
+                            if( (double)(Math.Abs(stp-stpc))<(double)(Math.Abs(stp-stpq)) )
+                            {
+                                stpf = stpc;
+                            }
+                            else
+                            {
+                                stpf = stpq;
+                            }
+                        }
+                        else
+                        {
+                            if( (double)(Math.Abs(stp-stpc))>(double)(Math.Abs(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;
+                        if( brackt )
+                        {
+                            theta = 3*(fp-fy)/(sty-stp)+dy+dp;
+                            s = Math.Max(Math.Abs(theta), Math.Max(Math.Abs(dy), Math.Abs(dp)));
+                            gamma = s*Math.Sqrt(AP.Math.Sqr(theta/s)-dy/s*(dp/s));
+                            if( (double)(stp)>(double)(sty) )
+                            {
+                                gamma = -gamma;
+                            }
+                            p = gamma-dp+theta;
+                            q = gamma-dp+gamma+dy;
+                            r = p/q;
+                            stpc = stp+r*(sty-stp);
+                            stpf = stpc;
+                        }
+                        else
+                        {
+                            if( (double)(stp)>(double)(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( (double)(fp)>(double)(fx) )
+            {
+                sty = stp;
+                fy = fp;
+                dy = dp;
+            }
+            else
+            {
+                if( (double)(sgnd)<(double)(0.0) )
+                {
+                    sty = stx;
+                    fy = fx;
+                    dy = dx;
+                }
+                stx = stp;
+                fx = fp;
+                dx = dp;
+            }
+            
+            //
+            //     COMPUTE THE NEW STEP AND SAFEGUARD IT.
+            //
+            stpf = Math.Min(stmax, stpf);
+            stpf = Math.Max(stmin, stpf);
+            stp = stpf;
+            if( brackt & bound )
+            {
+                if( (double)(sty)>(double)(stx) )
+                {
+                    stp = Math.Min(stx+0.66*(sty-stx), stp);
+                }
+                else
+                {
+                    stp = Math.Max(stx+0.66*(sty-stx), stp);
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lq.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lq.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lq.cs	(revision 2645)
@@ -0,0 +1,422 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class lq
+    {
+        /*************************************************************************
+        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).
+
+          -- ALGLIB --
+             Copyright 2005-2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixlq(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau)
+        {
+            double[] work = new double[0];
+            double[] t = new double[0];
+            int i = 0;
+            int k = 0;
+            int minmn = 0;
+            int maxmn = 0;
+            double tmp = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            minmn = Math.Min(m, n);
+            maxmn = Math.Max(m, n);
+            work = new double[m+1];
+            t = new double[n+1];
+            tau = new double[minmn-1+1];
+            k = Math.Min(m, n);
+            for(i=0; i<=k-1; i++)
+            {
+                
+                //
+                // Generate elementary reflector H(i) to annihilate A(i,i+1:n-1)
+                //
+                i1_ = (i) - (1);
+                for(i_=1; i_<=n-i;i_++)
+                {
+                    t[i_] = a[i,i_+i1_];
+                }
+                reflections.generatereflection(ref t, n-i, ref tmp);
+                tau[i] = tmp;
+                i1_ = (1) - (i);
+                for(i_=i; i_<=n-1;i_++)
+                {
+                    a[i,i_] = t[i_+i1_];
+                }
+                t[1] = 1;
+                if( i<n )
+                {
+                    
+                    //
+                    // Apply H(i) to A(i+1:m,i:n) from the right
+                    //
+                    reflections.applyreflectionfromtheright(ref a, tau[i], ref t, i+1, m-1, i, n-1, ref work);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Partial unpacking of matrix Q from the LQ decomposition of a matrix A
+
+        Input parameters:
+            A       -   matrices L and Q in compact form.
+                        Output of RMatrixLQ subroutine.
+            M       -   number of rows in given matrix A. M>=0.
+            N       -   number of columns in given matrix A. N>=0.
+            Tau     -   scalar factors which are used to form Q.
+                        Output of the RMatrixLQ subroutine.
+            QRows   -   required number of rows in matrix Q. N>=QRows>=0.
+
+        Output parameters:
+            Q       -   first QRows rows of matrix Q. Array whose indexes range
+                        within [0..QRows-1, 0..N-1]. If QRows=0, the array remains
+                        unchanged.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixlqunpackq(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau,
+            int qrows,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int minmn = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qrows<=n, "RMatrixLQUnpackQ: QRows>N!");
+            if( m<=0 | n<=0 | qrows<=0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            minmn = Math.Min(m, n);
+            k = Math.Min(minmn, qrows);
+            q = new double[qrows-1+1, n-1+1];
+            v = new double[n+1];
+            work = new double[qrows+1];
+            for(i=0; i<=qrows-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=k-1; i>=0; i--)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                i1_ = (i) - (1);
+                for(i_=1; i_<=n-i;i_++)
+                {
+                    v[i_] = a[i,i_+i1_];
+                }
+                v[1] = 1;
+                reflections.applyreflectionfromtheright(ref q, tau[i], ref v, 0, qrows-1, i, n-1, ref work);
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacking of matrix L from the LQ decomposition of a matrix A
+
+        Input parameters:
+            A       -   matrices Q and L in compact form.
+                        Output of RMatrixLQ subroutine.
+            M       -   number of rows in given matrix A. M>=0.
+            N       -   number of columns in given matrix A. N>=0.
+
+        Output parameters:
+            L       -   matrix L, array[0..M-1, 0..N-1].
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixlqunpackl(ref double[,] a,
+            int m,
+            int n,
+            ref double[,] l)
+        {
+            int i = 0;
+            int k = 0;
+            int i_ = 0;
+
+            if( m<=0 | n<=0 )
+            {
+                return;
+            }
+            l = new double[m-1+1, n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                l[0,i] = 0;
+            }
+            for(i=1; i<=m-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    l[i,i_] = l[0,i_];
+                }
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                k = Math.Min(i, n-1);
+                for(i_=0; i_<=k;i_++)
+                {
+                    l[i,i_] = a[i,i_];
+                }
+            }
+        }
+
+
+        public static void lqdecomposition(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau)
+        {
+            double[] work = new double[0];
+            double[] t = new double[0];
+            int i = 0;
+            int k = 0;
+            int nmip1 = 0;
+            int minmn = 0;
+            int maxmn = 0;
+            double tmp = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            minmn = Math.Min(m, n);
+            maxmn = Math.Max(m, n);
+            work = new double[m+1];
+            t = new double[n+1];
+            tau = new double[minmn+1];
+            
+            //
+            // Test the input arguments
+            //
+            k = Math.Min(m, n);
+            for(i=1; i<=k; i++)
+            {
+                
+                //
+                // Generate elementary reflector H(i) to annihilate A(i,i+1:n)
+                //
+                nmip1 = n-i+1;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=nmip1;i_++)
+                {
+                    t[i_] = a[i,i_+i1_];
+                }
+                reflections.generatereflection(ref t, nmip1, ref tmp);
+                tau[i] = tmp;
+                i1_ = (1) - (i);
+                for(i_=i; i_<=n;i_++)
+                {
+                    a[i,i_] = t[i_+i1_];
+                }
+                t[1] = 1;
+                if( i<n )
+                {
+                    
+                    //
+                    // Apply H(i) to A(i+1:m,i:n) from the right
+                    //
+                    reflections.applyreflectionfromtheright(ref a, tau[i], ref t, i+1, m, i, n, ref work);
+                }
+            }
+        }
+
+
+        public static void unpackqfromlq(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau,
+            int qrows,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int minmn = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qrows<=n, "UnpackQFromLQ: QRows>N!");
+            if( m==0 | n==0 | qrows==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            minmn = Math.Min(m, n);
+            k = Math.Min(minmn, qrows);
+            q = new double[qrows+1, n+1];
+            v = new double[n+1];
+            work = new double[qrows+1];
+            for(i=1; i<=qrows; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=k; i>=1; i--)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                vm = n-i+1;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=vm;i_++)
+                {
+                    v[i_] = a[i,i_+i1_];
+                }
+                v[1] = 1;
+                reflections.applyreflectionfromtheright(ref q, tau[i], ref v, 1, qrows, i, n, ref work);
+            }
+        }
+
+
+        public static void lqdecompositionunpacked(double[,] a,
+            int m,
+            int n,
+            ref double[,] l,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            double[] tau = new double[0];
+
+            a = (double[,])a.Clone();
+
+            if( n<=0 )
+            {
+                return;
+            }
+            q = new double[n+1, n+1];
+            l = new double[m+1, n+1];
+            
+            //
+            // LQDecomposition
+            //
+            lqdecomposition(ref a, m, n, ref tau);
+            
+            //
+            // L
+            //
+            for(i=1; i<=m; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( j>i )
+                    {
+                        l[i,j] = 0;
+                    }
+                    else
+                    {
+                        l[i,j] = a[i,j];
+                    }
+                }
+            }
+            
+            //
+            // Q
+            //
+            unpackqfromlq(ref a, m, n, ref tau, n, ref q);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lsfit.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lsfit.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lsfit.cs	(revision 2645)
@@ -0,0 +1,1547 @@
+/*************************************************************************
+Copyright (c) 2006-2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class lsfit
+    {
+        /*************************************************************************
+        Least squares fitting report:
+            TaskRCond       reciprocal of task's condition number
+            RMSError        RMS error
+            AvgError        average error
+            AvgRelError     average relative error (for non-zero Y[I])
+            MaxError        maximum error
+        *************************************************************************/
+        public struct lsfitreport
+        {
+            public double taskrcond;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+            public double maxerror;
+        };
+
+
+        public struct lsfitstate
+        {
+            public int n;
+            public int m;
+            public int k;
+            public double epsf;
+            public double epsx;
+            public int maxits;
+            public double[,] taskx;
+            public double[] tasky;
+            public double[] w;
+            public bool cheapfg;
+            public bool havehess;
+            public bool needf;
+            public bool needfg;
+            public bool needfgh;
+            public int pointindex;
+            public double[] x;
+            public double[] c;
+            public double f;
+            public double[] g;
+            public double[,] h;
+            public int repterminationtype;
+            public double reprmserror;
+            public double repavgerror;
+            public double repavgrelerror;
+            public double repmaxerror;
+            public minlm.lmstate optstate;
+            public minlm.lmreport optrep;
+            public AP.rcommstate rstate;
+        };
+
+
+
+
+        /*************************************************************************
+        Weighted linear least squares fitting.
+
+        QR decomposition is used to reduce task to MxM, then triangular solver  or
+        SVD-based solver is used depending on condition number of the  system.  It
+        allows to maximize speed and retain decent accuracy.
+
+        INPUT PARAMETERS:
+            Y       -   array[0..N-1] Function values in  N  points.
+            W       -   array[0..N-1]  Weights  corresponding to function  values.
+                        Each summand in square  sum  of  approximation  deviations
+                        from  given  values  is  multiplied  by  the   square   of
+                        corresponding weight.
+            FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
+                        FMatrix[I, J] - value of J-th basis function in I-th point.
+            N       -   number of points used. N>=1.
+            M       -   number of basis functions, M>=1.
+
+        OUTPUT PARAMETERS:
+            Info    -   error code:
+                        * -4    internal SVD decomposition subroutine failed (very
+                                rare and for degenerate systems only)
+                        * -1    incorrect N/M were specified
+                        *  1    task is solved
+            C       -   decomposition coefficients, array[0..M-1]
+            Rep     -   fitting report. Following fields are set:
+                        * Rep.TaskRCond     reciprocal of condition number
+                        * 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
+
+        SEE ALSO
+            LSFitLinear
+            LSFitLinearC
+            LSFitLinearWC
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitlinearw(ref double[] y,
+            ref double[] w,
+            ref double[,] fmatrix,
+            int n,
+            int m,
+            ref int info,
+            ref double[] c,
+            ref lsfitreport rep)
+        {
+            lsfitlinearinternal(ref y, ref w, ref fmatrix, n, m, ref info, ref c, ref rep);
+        }
+
+
+        /*************************************************************************
+        Weighted constained linear least squares fitting.
+
+        This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
+        that  K  additional  constaints  C*x=bc are satisfied. It reduces original
+        task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
+        is called.
+
+        INPUT PARAMETERS:
+            Y       -   array[0..N-1] Function values in  N  points.
+            W       -   array[0..N-1]  Weights  corresponding to function  values.
+                        Each summand in square  sum  of  approximation  deviations
+                        from  given  values  is  multiplied  by  the   square   of
+                        corresponding weight.
+            FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
+                        FMatrix[I,J] - value of J-th basis function in I-th point.
+            CMatrix -   a table of constaints, array[0..K-1,0..M].
+                        I-th row of CMatrix corresponds to I-th linear constraint:
+                        CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
+            N       -   number of points used. N>=1.
+            M       -   number of basis functions, M>=1.
+            K       -   number of constraints, 0 <= K < M
+                        K=0 corresponds to absence of constraints.
+
+        OUTPUT PARAMETERS:
+            Info    -   error code:
+                        * -4    internal SVD decomposition subroutine failed (very
+                                rare and for degenerate systems only)
+                        * -3    either   too   many  constraints  (M   or   more),
+                                degenerate  constraints   (some   constraints  are
+                                repetead twice) or inconsistent  constraints  were
+                                specified.
+                        * -1    incorrect N/M/K 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.
+
+        SEE ALSO
+            LSFitLinear
+            LSFitLinearC
+            LSFitLinearWC
+
+          -- ALGLIB --
+             Copyright 07.09.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitlinearwc(double[] y,
+            ref double[] w,
+            ref double[,] fmatrix,
+            double[,] cmatrix,
+            int n,
+            int m,
+            int k,
+            ref int info,
+            ref double[] c,
+            ref lsfitreport rep)
+        {
+            int i = 0;
+            int j = 0;
+            double[] tau = new double[0];
+            double[,] q = new double[0,0];
+            double[,] f2 = new double[0,0];
+            double[] tmp = new double[0];
+            double[] c0 = new double[0];
+            double v = 0;
+            int i_ = 0;
+
+            y = (double[])y.Clone();
+            cmatrix = (double[,])cmatrix.Clone();
+
+            if( n<1 | m<1 | k<0 )
+            {
+                info = -1;
+                return;
+            }
+            if( k>=m )
+            {
+                info = -3;
+                return;
+            }
+            
+            //
+            // Solve
+            //
+            if( k==0 )
+            {
+                
+                //
+                // no constraints
+                //
+                lsfitlinearinternal(ref y, ref w, ref fmatrix, n, m, ref info, ref c, ref 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.
+                //
+                lq.rmatrixlq(ref cmatrix, k, m, ref tau);
+                lq.rmatrixlqunpackq(ref cmatrix, k, m, ref tau, m, ref q);
+                for(i=0; i<=k-1; i++)
+                {
+                    for(j=i+1; j<=m-1; j++)
+                    {
+                        cmatrix[i,j] = 0.0;
+                    }
+                }
+                if( (double)(rcond.rmatrixlurcondinf(ref cmatrix, k))<(double)(1000*AP.Math.MachineEpsilon) )
+                {
+                    info = -3;
+                    return;
+                }
+                tmp = new double[k];
+                for(i=0; i<=k-1; i++)
+                {
+                    if( i>0 )
+                    {
+                        v = 0.0;
+                        for(i_=0; i_<=i-1;i_++)
+                        {
+                            v += cmatrix[i,i_]*tmp[i_];
+                        }
+                    }
+                    else
+                    {
+                        v = 0;
+                    }
+                    tmp[i] = (cmatrix[i,m]-v)/cmatrix[i,i];
+                }
+                c0 = new double[m];
+                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
+                //
+                tmp = new double[Math.Max(n, m)+1];
+                f2 = new double[n, m-k];
+                blas.matrixvectormultiply(ref fmatrix, 0, n-1, 0, m-1, false, ref c0, 0, m-1, -1.0, ref y, 0, n-1, 1.0);
+                blas.matrixmatrixmultiply(ref fmatrix, 0, n-1, 0, m-1, false, ref q, k, m-1, 0, m-1, true, 1.0, ref f2, 0, n-1, 0, m-k-1, 0.0, ref tmp);
+                lsfitlinearinternal(ref y, ref w, ref f2, n, m-k, ref info, ref tmp, ref rep);
+                rep.taskrcond = -1;
+                if( info<=0 )
+                {
+                    return;
+                }
+                
+                //
+                // then, convert back to original answer: C = C0 + Q2'*Y0
+                //
+                c = new double[m];
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    c[i_] = c0[i_];
+                }
+                blas.matrixvectormultiply(ref q, k, m-1, 0, m-1, true, ref tmp, 0, m-k-1, 1.0, ref c, 0, m-1, 1.0);
+            }
+        }
+
+
+        /*************************************************************************
+        Linear least squares fitting, without weights.
+
+        See LSFitLinearW for more information.
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitlinear(ref double[] y,
+            ref double[,] fmatrix,
+            int n,
+            int m,
+            ref int info,
+            ref double[] c,
+            ref lsfitreport rep)
+        {
+            double[] w = new double[0];
+            int i = 0;
+
+            if( n<1 )
+            {
+                info = -1;
+                return;
+            }
+            w = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                w[i] = 1;
+            }
+            lsfitlinearinternal(ref y, ref w, ref fmatrix, n, m, ref info, ref c, ref rep);
+        }
+
+
+        /*************************************************************************
+        Constained linear least squares fitting, without weights.
+
+        See LSFitLinearWC() for more information.
+
+          -- ALGLIB --
+             Copyright 07.09.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitlinearc(double[] y,
+            ref double[,] fmatrix,
+            ref double[,] cmatrix,
+            int n,
+            int m,
+            int k,
+            ref int info,
+            ref double[] c,
+            ref lsfitreport rep)
+        {
+            double[] w = new double[0];
+            int i = 0;
+
+            y = (double[])y.Clone();
+
+            if( n<1 )
+            {
+                info = -1;
+                return;
+            }
+            w = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                w[i] = 1;
+            }
+            lsfitlinearwc(y, ref w, ref fmatrix, cmatrix, n, m, k, ref info, ref c, ref rep);
+        }
+
+
+        /*************************************************************************
+        Weighted nonlinear least squares fitting using gradient and Hessian.
+
+        Nonlinear task min(F(c)) is solved, where
+
+            F(c) = (w[0]*(f(x[0],c)-y[0]))^2 + ... + (w[n-1]*(f(x[n-1],c)-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(x[i],c) 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
+            EpsF    -   stopping criterion. Algorithm stops if
+                        |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
+            EpsX    -   stopping criterion. Algorithm stops if
+                        |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
+            MaxIts  -   stopping criterion. Algorithm stops after MaxIts iterations.
+                        MaxIts=0 means no stopping criterion.
+            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 allows to save O(N*M^2) operations
+                                per iteration with  additional cost of N function/
+                                /gradient calculations.
+                        * False otherwise.
+                                Standard Jacibian-bases  Levenberg-Marquardt  algo
+                                will be used.
+
+        OUTPUT PARAMETERS:
+            State   -   structure which stores algorithm state between subsequent
+                        calls  of   LSFitNonlinearIteration.   Used  for  reverse
+                        communication.  This  structure   should   be  passed  to
+                        LSFitNonlinearIteration subroutine.
+
+        See also:
+            LSFitNonlinearIteration
+            LSFitNonlinearResults
+            LSFitNonlinearFG (fitting without weights)
+            LSFitNonlinearWFGH (fitting using Hessian)
+            LSFitNonlinearFGH (fitting using Hessian, without weights)
+
+        NOTE
+
+        Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
+        stopping criterion selection (small EpsX).
+
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitnonlinearwfg(ref double[,] x,
+            ref double[] y,
+            ref double[] w,
+            ref double[] c,
+            int n,
+            int m,
+            int k,
+            double epsf,
+            double epsx,
+            int maxits,
+            bool cheapfg,
+            ref lsfitstate state)
+        {
+            int i = 0;
+            int i_ = 0;
+
+            state.n = n;
+            state.m = m;
+            state.k = k;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.cheapfg = cheapfg;
+            state.havehess = false;
+            if( n>=1 & m>=1 & k>=1 )
+            {
+                state.taskx = new double[n, m];
+                state.tasky = new double[n];
+                state.w = new double[n];
+                state.c = new double[k];
+                for(i_=0; i_<=k-1;i_++)
+                {
+                    state.c[i_] = c[i_];
+                }
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.w[i_] = w[i_];
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        state.taskx[i,i_] = x[i,i_];
+                    }
+                    state.tasky[i] = y[i];
+                }
+            }
+            state.rstate.ia = new int[4+1];
+            state.rstate.ra = new double[1+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        Nonlinear least squares fitting, no individual weights.
+        See LSFitNonlinearWFG for more information.
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitnonlinearfg(ref double[,] x,
+            ref double[] y,
+            ref double[] c,
+            int n,
+            int m,
+            int k,
+            double epsf,
+            double epsx,
+            int maxits,
+            bool cheapfg,
+            ref lsfitstate state)
+        {
+            int i = 0;
+            int i_ = 0;
+
+            state.n = n;
+            state.m = m;
+            state.k = k;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.cheapfg = cheapfg;
+            state.havehess = false;
+            if( n>=1 & m>=1 & k>=1 )
+            {
+                state.taskx = new double[n, m];
+                state.tasky = new double[n];
+                state.w = new double[n];
+                state.c = new double[k];
+                for(i_=0; i_<=k-1;i_++)
+                {
+                    state.c[i_] = c[i_];
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        state.taskx[i,i_] = x[i,i_];
+                    }
+                    state.tasky[i] = y[i];
+                    state.w[i] = 1;
+                }
+            }
+            state.rstate.ia = new int[4+1];
+            state.rstate.ra = new double[1+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        Weighted nonlinear least squares fitting using gradient/Hessian.
+
+        Nonlinear task min(F(c)) is solved, where
+
+            F(c) = (w[0]*(f(x[0],c)-y[0]))^2 + ... + (w[n-1]*(f(x[n-1],c)-y[n-1]))^2,
+
+            * N is a number of points,
+            * M is a dimension of a space points belong to,
+            * K is a dimension of a space of parameters being fitted,
+            * w is an N-dimensional vector of weight coefficients,
+            * x is a set of N points, each of them is an M-dimensional vector,
+            * c is a K-dimensional vector of parameters being fitted
+
+        This subroutine uses f(x[i],c), its gradient and its Hessian.
+
+        See LSFitNonlinearWFG() subroutine for information about function
+        parameters.
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitnonlinearwfgh(ref double[,] x,
+            ref double[] y,
+            ref double[] w,
+            ref double[] c,
+            int n,
+            int m,
+            int k,
+            double epsf,
+            double epsx,
+            int maxits,
+            ref lsfitstate state)
+        {
+            int i = 0;
+            int i_ = 0;
+
+            state.n = n;
+            state.m = m;
+            state.k = k;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.cheapfg = true;
+            state.havehess = true;
+            if( n>=1 & m>=1 & k>=1 )
+            {
+                state.taskx = new double[n, m];
+                state.tasky = new double[n];
+                state.w = new double[n];
+                state.c = new double[k];
+                for(i_=0; i_<=k-1;i_++)
+                {
+                    state.c[i_] = c[i_];
+                }
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.w[i_] = w[i_];
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        state.taskx[i,i_] = x[i,i_];
+                    }
+                    state.tasky[i] = y[i];
+                }
+            }
+            state.rstate.ia = new int[4+1];
+            state.rstate.ra = new double[1+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        Nonlinear least squares fitting using gradient/Hessian without  individual
+        weights. See LSFitNonlinearWFGH() for more information.
+
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitnonlinearfgh(ref double[,] x,
+            ref double[] y,
+            ref double[] c,
+            int n,
+            int m,
+            int k,
+            double epsf,
+            double epsx,
+            int maxits,
+            ref lsfitstate state)
+        {
+            int i = 0;
+            int i_ = 0;
+
+            state.n = n;
+            state.m = m;
+            state.k = k;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.cheapfg = true;
+            state.havehess = true;
+            if( n>=1 & m>=1 & k>=1 )
+            {
+                state.taskx = new double[n, m];
+                state.tasky = new double[n];
+                state.w = new double[n];
+                state.c = new double[k];
+                for(i_=0; i_<=k-1;i_++)
+                {
+                    state.c[i_] = c[i_];
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        state.taskx[i,i_] = x[i,i_];
+                    }
+                    state.tasky[i] = y[i];
+                    state.w[i] = 1;
+                }
+            }
+            state.rstate.ia = new int[4+1];
+            state.rstate.ra = new double[1+1];
+            state.rstate.stage = -1;
+        }
+
+
+        /*************************************************************************
+        Nonlinear least squares fitting. Algorithm iteration.
+
+        Called after inialization of the State structure with  LSFitNonlinearXXX()
+        subroutine. See HTML docs for examples.
+
+        INPUT PARAMETERS:
+            State   -   structure which stores algorithm state between  subsequent
+                        calls and which is used for reverse communication. Must be
+                        initialized with LSFitNonlinearXXX() call first.
+
+        RESULT
+        1. If subroutine returned False, iterative algorithm has converged.
+        2. If subroutine returned True, then if:
+        * if State.NeedF=True,      function value F(X,C) is required
+        * if State.NeedFG=True,     function value F(X,C) and gradient  dF/dC(X,C)
+                                    are required
+        * if State.NeedFGH=True     function value F(X,C), gradient dF/dC(X,C) and
+                                    Hessian are required
+
+        One and only one of this fields can be set at time.
+
+        Function, its gradient and Hessian are calculated at  (X,C),  where  X  is
+        stored in State.X[0..M-1] and C is stored in State.C[0..K-1].
+
+        Results are stored:
+        * function value            -   in State.F
+        * gradient                  -   in State.G[0..K-1]
+        * Hessian                   -   in State.H[0..K-1,0..K-1]
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool lsfitnonlineariteration(ref lsfitstate state)
+        {
+            bool result = new bool();
+            int n = 0;
+            int m = 0;
+            int k = 0;
+            int i = 0;
+            int j = 0;
+            double v = 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.rstate.stage>=0 )
+            {
+                n = state.rstate.ia[0];
+                m = state.rstate.ia[1];
+                k = state.rstate.ia[2];
+                i = state.rstate.ia[3];
+                j = state.rstate.ia[4];
+                v = state.rstate.ra[0];
+                relcnt = state.rstate.ra[1];
+            }
+            else
+            {
+                n = -983;
+                m = -989;
+                k = -834;
+                i = 900;
+                j = -287;
+                v = 364;
+                relcnt = 214;
+            }
+            if( state.rstate.stage==0 )
+            {
+                goto lbl_0;
+            }
+            if( state.rstate.stage==1 )
+            {
+                goto lbl_1;
+            }
+            if( state.rstate.stage==2 )
+            {
+                goto lbl_2;
+            }
+            if( state.rstate.stage==3 )
+            {
+                goto lbl_3;
+            }
+            if( state.rstate.stage==4 )
+            {
+                goto lbl_4;
+            }
+            
+            //
+            // Routine body
+            //
+            
+            //
+            // check params
+            //
+            if( state.n<1 | state.m<1 | state.k<1 | (double)(state.epsf)<(double)(0) | (double)(state.epsx)<(double)(0) | state.maxits<0 )
+            {
+                state.repterminationtype = -1;
+                result = false;
+                return result;
+            }
+            
+            //
+            // init
+            //
+            n = state.n;
+            m = state.m;
+            k = state.k;
+            state.x = new double[m];
+            state.g = new double[k];
+            if( state.havehess )
+            {
+                state.h = new double[k, k];
+            }
+            
+            //
+            // initialize LM optimizer
+            //
+            if( state.havehess )
+            {
+                
+                //
+                // use Hessian.
+                // transform stopping conditions.
+                //
+                minlm.minlmfgh(k, ref state.c, AP.Math.Sqr(state.epsf)*n, state.epsx, state.maxits, ref state.optstate);
+            }
+            else
+            {
+                
+                //
+                // use one of gradient-based schemes (depending on gradient cost).
+                // transform stopping conditions.
+                //
+                if( state.cheapfg )
+                {
+                    minlm.minlmfgj(k, n, ref state.c, AP.Math.Sqr(state.epsf)*n, state.epsx, state.maxits, ref state.optstate);
+                }
+                else
+                {
+                    minlm.minlmfj(k, n, ref state.c, AP.Math.Sqr(state.epsf)*n, state.epsx, state.maxits, ref state.optstate);
+                }
+            }
+            
+            //
+            // Optimize
+            //
+        lbl_5:
+            if( ! minlm.minlmiteration(ref state.optstate) )
+            {
+                goto lbl_6;
+            }
+            if( ! state.optstate.needf )
+            {
+                goto lbl_7;
+            }
+            
+            //
+            // calculate F = sum (wi*(f(xi,c)-yi))^2
+            //
+            state.optstate.f = 0;
+            i = 0;
+        lbl_9:
+            if( i>n-1 )
+            {
+                goto lbl_11;
+            }
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.c[i_] = state.optstate.x[i_];
+            }
+            for(i_=0; i_<=m-1;i_++)
+            {
+                state.x[i_] = state.taskx[i,i_];
+            }
+            state.pointindex = i;
+            lsfitclearrequestfields(ref state);
+            state.needf = true;
+            state.rstate.stage = 0;
+            goto lbl_rcomm;
+        lbl_0:
+            state.optstate.f = state.optstate.f+AP.Math.Sqr(state.w[i]*(state.f-state.tasky[i]));
+            i = i+1;
+            goto lbl_9;
+        lbl_11:
+            goto lbl_5;
+        lbl_7:
+            if( ! state.optstate.needfg )
+            {
+                goto lbl_12;
+            }
+            
+            //
+            // calculate F/gradF
+            //
+            state.optstate.f = 0;
+            for(i=0; i<=k-1; i++)
+            {
+                state.optstate.g[i] = 0;
+            }
+            i = 0;
+        lbl_14:
+            if( i>n-1 )
+            {
+                goto lbl_16;
+            }
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.c[i_] = state.optstate.x[i_];
+            }
+            for(i_=0; i_<=m-1;i_++)
+            {
+                state.x[i_] = state.taskx[i,i_];
+            }
+            state.pointindex = i;
+            lsfitclearrequestfields(ref state);
+            state.needfg = true;
+            state.rstate.stage = 1;
+            goto lbl_rcomm;
+        lbl_1:
+            state.optstate.f = state.optstate.f+AP.Math.Sqr(state.w[i]*(state.f-state.tasky[i]));
+            v = AP.Math.Sqr(state.w[i])*2*(state.f-state.tasky[i]);
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_];
+            }
+            i = i+1;
+            goto lbl_14;
+        lbl_16:
+            goto lbl_5;
+        lbl_12:
+            if( ! state.optstate.needfij )
+            {
+                goto lbl_17;
+            }
+            
+            //
+            // calculate Fi/jac(Fi)
+            //
+            i = 0;
+        lbl_19:
+            if( i>n-1 )
+            {
+                goto lbl_21;
+            }
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.c[i_] = state.optstate.x[i_];
+            }
+            for(i_=0; i_<=m-1;i_++)
+            {
+                state.x[i_] = state.taskx[i,i_];
+            }
+            state.pointindex = i;
+            lsfitclearrequestfields(ref state);
+            state.needfg = true;
+            state.rstate.stage = 2;
+            goto lbl_rcomm;
+        lbl_2:
+            state.optstate.fi[i] = state.w[i]*(state.f-state.tasky[i]);
+            v = state.w[i];
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.optstate.j[i,i_] = v*state.g[i_];
+            }
+            i = i+1;
+            goto lbl_19;
+        lbl_21:
+            goto lbl_5;
+        lbl_17:
+            if( ! state.optstate.needfgh )
+            {
+                goto lbl_22;
+            }
+            
+            //
+            // calculate F/grad(F)/hess(F)
+            //
+            state.optstate.f = 0;
+            for(i=0; i<=k-1; i++)
+            {
+                state.optstate.g[i] = 0;
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                for(j=0; j<=k-1; j++)
+                {
+                    state.optstate.h[i,j] = 0;
+                }
+            }
+            i = 0;
+        lbl_24:
+            if( i>n-1 )
+            {
+                goto lbl_26;
+            }
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.c[i_] = state.optstate.x[i_];
+            }
+            for(i_=0; i_<=m-1;i_++)
+            {
+                state.x[i_] = state.taskx[i,i_];
+            }
+            state.pointindex = i;
+            lsfitclearrequestfields(ref state);
+            state.needfgh = true;
+            state.rstate.stage = 3;
+            goto lbl_rcomm;
+        lbl_3:
+            state.optstate.f = state.optstate.f+AP.Math.Sqr(state.w[i]*(state.f-state.tasky[i]));
+            v = AP.Math.Sqr(state.w[i])*2*(state.f-state.tasky[i]);
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.optstate.g[i_] = state.optstate.g[i_] + v*state.g[i_];
+            }
+            for(j=0; j<=k-1; j++)
+            {
+                v = 2*AP.Math.Sqr(state.w[i])*state.g[j];
+                for(i_=0; i_<=k-1;i_++)
+                {
+                    state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.g[i_];
+                }
+                v = 2*AP.Math.Sqr(state.w[i])*(state.f-state.tasky[i]);
+                for(i_=0; i_<=k-1;i_++)
+                {
+                    state.optstate.h[j,i_] = state.optstate.h[j,i_] + v*state.h[j,i_];
+                }
+            }
+            i = i+1;
+            goto lbl_24;
+        lbl_26:
+            goto lbl_5;
+        lbl_22:
+            goto lbl_5;
+        lbl_6:
+            minlm.minlmresults(ref state.optstate, ref state.c, ref state.optrep);
+            state.repterminationtype = state.optrep.terminationtype;
+            
+            //
+            // calculate errors
+            //
+            if( state.repterminationtype<=0 )
+            {
+                goto lbl_27;
+            }
+            state.reprmserror = 0;
+            state.repavgerror = 0;
+            state.repavgrelerror = 0;
+            state.repmaxerror = 0;
+            relcnt = 0;
+            i = 0;
+        lbl_29:
+            if( i>n-1 )
+            {
+                goto lbl_31;
+            }
+            for(i_=0; i_<=k-1;i_++)
+            {
+                state.c[i_] = state.c[i_];
+            }
+            for(i_=0; i_<=m-1;i_++)
+            {
+                state.x[i_] = state.taskx[i,i_];
+            }
+            state.pointindex = i;
+            lsfitclearrequestfields(ref state);
+            state.needf = true;
+            state.rstate.stage = 4;
+            goto lbl_rcomm;
+        lbl_4:
+            v = state.f;
+            state.reprmserror = state.reprmserror+AP.Math.Sqr(v-state.tasky[i]);
+            state.repavgerror = state.repavgerror+Math.Abs(v-state.tasky[i]);
+            if( (double)(state.tasky[i])!=(double)(0) )
+            {
+                state.repavgrelerror = state.repavgrelerror+Math.Abs(v-state.tasky[i])/Math.Abs(state.tasky[i]);
+                relcnt = relcnt+1;
+            }
+            state.repmaxerror = Math.Max(state.repmaxerror, Math.Abs(v-state.tasky[i]));
+            i = i+1;
+            goto lbl_29;
+        lbl_31:
+            state.reprmserror = Math.Sqrt(state.reprmserror/n);
+            state.repavgerror = state.repavgerror/n;
+            if( (double)(relcnt)!=(double)(0) )
+            {
+                state.repavgrelerror = state.repavgrelerror/relcnt;
+            }
+        lbl_27:
+            result = false;
+            return result;
+            
+            //
+            // Saving state
+            //
+        lbl_rcomm:
+            result = true;
+            state.rstate.ia[0] = n;
+            state.rstate.ia[1] = m;
+            state.rstate.ia[2] = k;
+            state.rstate.ia[3] = i;
+            state.rstate.ia[4] = j;
+            state.rstate.ra[0] = v;
+            state.rstate.ra[1] = relcnt;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Nonlinear least squares fitting results.
+
+        Called after LSFitNonlinearIteration() returned False.
+
+        INPUT PARAMETERS:
+            State   -   algorithm state (used by LSFitNonlinearIteration).
+
+        OUTPUT PARAMETERS:
+            Info    -   completetion code:
+                            * -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
+            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
+
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void lsfitnonlinearresults(ref lsfitstate state,
+            ref int info,
+            ref double[] c,
+            ref lsfitreport rep)
+        {
+            int i_ = 0;
+
+            info = state.repterminationtype;
+            if( info>0 )
+            {
+                c = new double[state.k];
+                for(i_=0; i_<=state.k-1;i_++)
+                {
+                    c[i_] = state.c[i_];
+                }
+                rep.rmserror = state.reprmserror;
+                rep.avgerror = state.repavgerror;
+                rep.avgrelerror = state.repavgrelerror;
+                rep.maxerror = state.repmaxerror;
+            }
+        }
+
+
+        public static void lsfitscalexy(ref double[] x,
+            ref double[] y,
+            int n,
+            ref double[] xc,
+            ref double[] yc,
+            ref int[] dc,
+            int k,
+            ref double xa,
+            ref double xb,
+            ref double sa,
+            ref double sb,
+            ref double[] xoriginal,
+            ref double[] yoriginal)
+        {
+            double v = 0;
+            double xmin = 0;
+            double xmax = 0;
+            int i = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "LSFitScaleXY: incorrect N");
+            System.Diagnostics.Debug.Assert(k>=0, "LSFitScaleXY: incorrect K");
+            
+            //
+            // Calculate xmin/xmax.
+            // Force xmin<>xmax.
+            //
+            xmin = x[0];
+            xmax = x[0];
+            for(i=1; i<=n-1; i++)
+            {
+                xmin = Math.Min(xmin, x[i]);
+                xmax = Math.Max(xmax, x[i]);
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                xmin = Math.Min(xmin, xc[i]);
+                xmax = Math.Max(xmax, xc[i]);
+            }
+            if( (double)(xmin)==(double)(xmax) )
+            {
+                if( (double)(xmin)==(double)(0) )
+                {
+                    xmin = -1;
+                    xmax = +1;
+                }
+                else
+                {
+                    xmin = 0.5*xmin;
+                }
+            }
+            
+            //
+            // Transform abscissas: map [XA,XB] to [0,1]
+            //
+            // Store old X[] in XOriginal[] (it will be used
+            // to calculate relative error).
+            //
+            xoriginal = new double[n];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                xoriginal[i_] = x[i_];
+            }
+            xa = xmin;
+            xb = xmax;
+            for(i=0; i<=n-1; i++)
+            {
+                x[i] = 2*(x[i]-0.5*(xa+xb))/(xb-xa);
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                System.Diagnostics.Debug.Assert(dc[i]>=0, "LSFitScaleXY: internal error!");
+                xc[i] = 2*(xc[i]-0.5*(xa+xb))/(xb-xa);
+                yc[i] = yc[i]*Math.Pow(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).
+            //
+            yoriginal = new double[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;
+            sb = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                sb = sb+AP.Math.Sqr(y[i]-sa);
+            }
+            sb = Math.Sqrt(sb/n)+sa;
+            if( (double)(sb)==(double)(sa) )
+            {
+                sb = 2*sa;
+            }
+            if( (double)(sb)==(double)(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++)
+            {
+                if( dc[i]==0 )
+                {
+                    yc[i] = (yc[i]-sa)/(sb-sa);
+                }
+                else
+                {
+                    yc[i] = yc[i]/(sb-sa);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal fitting subroutine
+        *************************************************************************/
+        private static void lsfitlinearinternal(ref double[] y,
+            ref double[] w,
+            ref double[,] fmatrix,
+            int n,
+            int m,
+            ref int info,
+            ref double[] c,
+            ref lsfitreport rep)
+        {
+            double threshold = 0;
+            double[,] ft = new double[0,0];
+            double[,] q = new double[0,0];
+            double[,] l = new double[0,0];
+            double[,] r = new double[0,0];
+            double[] b = new double[0];
+            double[] wmod = new double[0];
+            double[] tau = new double[0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            double[] sv = new double[0];
+            double[,] u = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] tmp = new double[0];
+            double[] utb = new double[0];
+            double[] sutb = new double[0];
+            int relcnt = 0;
+            int i_ = 0;
+
+            if( n<1 | m<1 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            threshold = 1000*AP.Math.MachineEpsilon;
+            
+            //
+            // Degenerate case, needs special handling
+            //
+            if( n<m )
+            {
+                
+                //
+                // Create design matrix.
+                //
+                ft = new double[n, m];
+                b = new double[n];
+                wmod = new double[n];
+                for(j=0; j<=n-1; j++)
+                {
+                    v = w[j];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        ft[j,i_] = v*fmatrix[j,i_];
+                    }
+                    b[j] = w[j]*y[j];
+                    wmod[j] = 1;
+                }
+                
+                //
+                // LQ decomposition and reduction to M=N
+                //
+                c = new double[m];
+                for(i=0; i<=m-1; i++)
+                {
+                    c[i] = 0;
+                }
+                rep.taskrcond = 0;
+                lq.rmatrixlq(ref ft, n, m, ref tau);
+                lq.rmatrixlqunpackq(ref ft, n, m, ref tau, n, ref q);
+                lq.rmatrixlqunpackl(ref ft, n, m, ref l);
+                lsfitlinearinternal(ref b, ref wmod, ref l, n, n, ref info, ref tmp, ref rep);
+                if( info<=0 )
+                {
+                    return;
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    v = tmp[i];
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        c[i_] = c[i_] + v*q[i,i_];
+                    }
+                }
+                return;
+            }
+            
+            //
+            // N>=M. Generate design matrix and reduce to N=M using
+            // QR decomposition.
+            //
+            ft = new double[n, m];
+            b = new double[n];
+            for(j=0; j<=n-1; j++)
+            {
+                v = w[j];
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    ft[j,i_] = v*fmatrix[j,i_];
+                }
+                b[j] = w[j]*y[j];
+            }
+            qr.rmatrixqr(ref ft, n, m, ref tau);
+            qr.rmatrixqrunpackq(ref ft, n, m, ref tau, m, ref q);
+            qr.rmatrixqrunpackr(ref ft, n, m, ref r);
+            tmp = new double[m];
+            for(i=0; i<=m-1; i++)
+            {
+                tmp[i] = 0;
+            }
+            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_];
+                }
+            }
+            b = new double[m];
+            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.taskrcond = rcond.rmatrixlurcondinf(ref r, m);
+            if( (double)(rep.taskrcond)>(double)(threshold) )
+            {
+                
+                //
+                // use QR-based solver
+                //
+                c = new double[m];
+                c[m-1] = b[m-1]/r[m-1,m-1];
+                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( !svd.rmatrixsvd(r, m, m, 1, 1, 2, ref sv, ref u, ref vt) )
+                {
+                    info = -4;
+                    return;
+                }
+                utb = new double[m];
+                sutb = new double[m];
+                for(i=0; i<=m-1; i++)
+                {
+                    utb[i] = 0;
+                }
+                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_];
+                    }
+                }
+                if( (double)(sv[0])>(double)(0) )
+                {
+                    rep.taskrcond = sv[m-1]/sv[0];
+                    for(i=0; i<=m-1; i++)
+                    {
+                        if( (double)(sv[i])>(double)(threshold*sv[0]) )
+                        {
+                            sutb[i] = utb[i]/sv[i];
+                        }
+                        else
+                        {
+                            sutb[i] = 0;
+                        }
+                    }
+                }
+                else
+                {
+                    rep.taskrcond = 0;
+                    for(i=0; i<=m-1; i++)
+                    {
+                        sutb[i] = 0;
+                    }
+                }
+                c = new double[m];
+                for(i=0; i<=m-1; i++)
+                {
+                    c[i] = 0;
+                }
+                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.rmserror = 0;
+            rep.avgerror = 0;
+            rep.avgrelerror = 0;
+            rep.maxerror = 0;
+            relcnt = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                v = 0.0;
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    v += fmatrix[i,i_]*c[i_];
+                }
+                rep.rmserror = rep.rmserror+AP.Math.Sqr(v-y[i]);
+                rep.avgerror = rep.avgerror+Math.Abs(v-y[i]);
+                if( (double)(y[i])!=(double)(0) )
+                {
+                    rep.avgrelerror = rep.avgrelerror+Math.Abs(v-y[i])/Math.Abs(y[i]);
+                    relcnt = relcnt+1;
+                }
+                rep.maxerror = Math.Max(rep.maxerror, Math.Abs(v-y[i]));
+            }
+            rep.rmserror = Math.Sqrt(rep.rmserror/n);
+            rep.avgerror = rep.avgerror/n;
+            if( relcnt!=0 )
+            {
+                rep.avgrelerror = rep.avgrelerror/relcnt;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+        *************************************************************************/
+        private static void lsfitclearrequestfields(ref lsfitstate state)
+        {
+            state.needf = false;
+            state.needfg = false;
+            state.needfgh = false;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lu.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lu.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/lu.cs	(revision 2645)
@@ -0,0 +1,509 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee. All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class lu
+    {
+        public const int lunb = 8;
+
+
+        /*************************************************************************
+        LU decomposition of a general matrix of size MxN
+
+        The subroutine calculates the LU decomposition of a rectangular general
+        matrix with partial pivoting (with row permutations).
+
+        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 U in compact form (see below).
+                    Array whose indexes range within [0..M-1, 0..N-1].
+            Pivots - permutation matrix in compact form (see below).
+                    Array whose index ranges within [0..Min(M-1,N-1)].
+
+        Matrix A is represented as A = P * L * U, where P is a permutation matrix,
+        matrix L - lower triangular (or lower trapezoid, if M>N) matrix,
+        U - upper triangular (or upper trapezoid, if M<N) matrix.
+
+        Let M be equal to 4 and N be equal to 3:
+
+                           (  1          )    ( U11 U12 U13  )
+        A = P1 * P2 * P3 * ( L21  1      )  * (     U22 U23  )
+                           ( L31 L32  1  )    (         U33  )
+                           ( L41 L42 L43 )
+
+        Matrix L has size MxMin(M,N), matrix U has size Min(M,N)xN, matrix P(i) is
+        a permutation of the identity matrix of size MxM with numbers I and Pivots[I].
+
+        The algorithm returns array Pivots and the following matrix which replaces
+        matrix A and contains matrices L and U in compact form (the example applies
+        to M=4, N=3).
+
+         ( U11 U12 U13 )
+         ( L21 U22 U23 )
+         ( L31 L32 U33 )
+         ( L41 L42 L43 )
+
+        As we can see, the unit diagonal isn't stored.
+
+          -- LAPACK routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             June 30, 1992
+        *************************************************************************/
+        public static void rmatrixlu(ref double[,] a,
+            int m,
+            int n,
+            ref int[] pivots)
+        {
+            double[,] b = new double[0,0];
+            double[] t = new double[0];
+            int[] bp = new int[0];
+            int minmn = 0;
+            int i = 0;
+            int ip = 0;
+            int j = 0;
+            int j1 = 0;
+            int j2 = 0;
+            int cb = 0;
+            int nb = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(lunb>=1, "RMatrixLU internal error");
+            nb = lunb;
+            
+            //
+            // Decide what to use - blocked or unblocked code
+            //
+            if( n<=1 | Math.Min(m, n)<=nb | nb==1 )
+            {
+                
+                //
+                // Unblocked code
+                //
+                rmatrixlu2(ref a, m, n, ref pivots);
+            }
+            else
+            {
+                
+                //
+                // Blocked code.
+                // First, prepare temporary matrix and indices
+                //
+                b = new double[m-1+1, nb-1+1];
+                t = new double[n-1+1];
+                pivots = new int[Math.Min(m, n)-1+1];
+                minmn = Math.Min(m, n);
+                j1 = 0;
+                j2 = Math.Min(minmn, nb)-1;
+                
+                //
+                // Main cycle
+                //
+                while( j1<minmn )
+                {
+                    cb = j2-j1+1;
+                    
+                    //
+                    // LU factorization of diagonal and subdiagonal blocks:
+                    // 1. Copy columns J1..J2 of A to B
+                    // 2. LU(B)
+                    // 3. Copy result back to A
+                    // 4. Copy pivots, apply pivots
+                    //
+                    for(i=j1; i<=m-1; i++)
+                    {
+                        i1_ = (j1) - (0);
+                        for(i_=0; i_<=cb-1;i_++)
+                        {
+                            b[i-j1,i_] = a[i,i_+i1_];
+                        }
+                    }
+                    rmatrixlu2(ref b, m-j1, cb, ref bp);
+                    for(i=j1; i<=m-1; i++)
+                    {
+                        i1_ = (0) - (j1);
+                        for(i_=j1; i_<=j2;i_++)
+                        {
+                            a[i,i_] = b[i-j1,i_+i1_];
+                        }
+                    }
+                    for(i=0; i<=cb-1; i++)
+                    {
+                        ip = bp[i];
+                        pivots[j1+i] = j1+ip;
+                        if( bp[i]!=i )
+                        {
+                            if( j1!=0 )
+                            {
+                                
+                                //
+                                // Interchange columns 0:J1-1
+                                //
+                                for(i_=0; i_<=j1-1;i_++)
+                                {
+                                    t[i_] = a[j1+i,i_];
+                                }
+                                for(i_=0; i_<=j1-1;i_++)
+                                {
+                                    a[j1+i,i_] = a[j1+ip,i_];
+                                }
+                                for(i_=0; i_<=j1-1;i_++)
+                                {
+                                    a[j1+ip,i_] = t[i_];
+                                }
+                            }
+                            if( j2<n-1 )
+                            {
+                                
+                                //
+                                // Interchange the rest of the matrix, if needed
+                                //
+                                for(i_=j2+1; i_<=n-1;i_++)
+                                {
+                                    t[i_] = a[j1+i,i_];
+                                }
+                                for(i_=j2+1; i_<=n-1;i_++)
+                                {
+                                    a[j1+i,i_] = a[j1+ip,i_];
+                                }
+                                for(i_=j2+1; i_<=n-1;i_++)
+                                {
+                                    a[j1+ip,i_] = t[i_];
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Compute block row of U
+                    //
+                    if( j2<n-1 )
+                    {
+                        for(i=j1+1; i<=j2; i++)
+                        {
+                            for(j=j1; j<=i-1; j++)
+                            {
+                                v = a[i,j];
+                                for(i_=j2+1; i_<=n-1;i_++)
+                                {
+                                    a[i,i_] = a[i,i_] - v*a[j,i_];
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Update trailing submatrix
+                    //
+                    if( j2<n-1 )
+                    {
+                        for(i=j2+1; i<=m-1; i++)
+                        {
+                            for(j=j1; j<=j2; j++)
+                            {
+                                v = a[i,j];
+                                for(i_=j2+1; i_<=n-1;i_++)
+                                {
+                                    a[i,i_] = a[i,i_] - v*a[j,i_];
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // Next step
+                    //
+                    j1 = j2+1;
+                    j2 = Math.Min(minmn, j1+nb)-1;
+                }
+            }
+        }
+
+
+        public static void ludecomposition(ref double[,] a,
+            int m,
+            int n,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int j = 0;
+            int jp = 0;
+            double[] t1 = new double[0];
+            double s = 0;
+            int i_ = 0;
+
+            pivots = new int[Math.Min(m, n)+1];
+            t1 = new double[Math.Max(m, n)+1];
+            System.Diagnostics.Debug.Assert(m>=0 & n>=0, "Error in LUDecomposition: incorrect function arguments");
+            
+            //
+            // Quick return if possible
+            //
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            for(j=1; j<=Math.Min(m, n); j++)
+            {
+                
+                //
+                // Find pivot and test for singularity.
+                //
+                jp = j;
+                for(i=j+1; i<=m; i++)
+                {
+                    if( (double)(Math.Abs(a[i,j]))>(double)(Math.Abs(a[jp,j])) )
+                    {
+                        jp = i;
+                    }
+                }
+                pivots[j] = jp;
+                if( (double)(a[jp,j])!=(double)(0) )
+                {
+                    
+                    //
+                    //Apply the interchange to rows
+                    //
+                    if( jp!=j )
+                    {
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            t1[i_] = a[j,i_];
+                        }
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            a[j,i_] = a[jp,i_];
+                        }
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            a[jp,i_] = t1[i_];
+                        }
+                    }
+                    
+                    //
+                    //Compute elements J+1:M of J-th column.
+                    //
+                    if( j<m )
+                    {
+                        
+                        //
+                        // CALL DSCAL( M-J, ONE / A( J, J ), A( J+1, J ), 1 )
+                        //
+                        jp = j+1;
+                        s = 1/a[j,j];
+                        for(i_=jp; i_<=m;i_++)
+                        {
+                            a[i_,j] = s*a[i_,j];
+                        }
+                    }
+                }
+                if( j<Math.Min(m, n) )
+                {
+                    
+                    //
+                    //Update trailing submatrix.
+                    //CALL DGER( M-J, N-J, -ONE, A( J+1, J ), 1, A( J, J+1 ), LDA,A( J+1, J+1 ), LDA )
+                    //
+                    jp = j+1;
+                    for(i=j+1; i<=m; i++)
+                    {
+                        s = a[i,j];
+                        for(i_=jp; i_<=n;i_++)
+                        {
+                            a[i,i_] = a[i,i_] - s*a[j,i_];
+                        }
+                    }
+                }
+            }
+        }
+
+
+        public static void ludecompositionunpacked(double[,] a,
+            int m,
+            int n,
+            ref double[,] l,
+            ref double[,] u,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int j = 0;
+            int minmn = 0;
+
+            a = (double[,])a.Clone();
+
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            minmn = Math.Min(m, n);
+            l = new double[m+1, minmn+1];
+            u = new double[minmn+1, n+1];
+            ludecomposition(ref a, m, n, ref pivots);
+            for(i=1; i<=m; i++)
+            {
+                for(j=1; j<=minmn; j++)
+                {
+                    if( j>i )
+                    {
+                        l[i,j] = 0;
+                    }
+                    if( j==i )
+                    {
+                        l[i,j] = 1;
+                    }
+                    if( j<i )
+                    {
+                        l[i,j] = a[i,j];
+                    }
+                }
+            }
+            for(i=1; i<=minmn; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( j<i )
+                    {
+                        u[i,j] = 0;
+                    }
+                    if( j>=i )
+                    {
+                        u[i,j] = a[i,j];
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Level 2 BLAS version of RMatrixLU
+
+          -- LAPACK routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             June 30, 1992
+        *************************************************************************/
+        private static void rmatrixlu2(ref double[,] a,
+            int m,
+            int n,
+            ref int[] pivots)
+        {
+            int i = 0;
+            int j = 0;
+            int jp = 0;
+            double[] t1 = new double[0];
+            double s = 0;
+            int i_ = 0;
+
+            pivots = new int[Math.Min(m-1, n-1)+1];
+            t1 = new double[Math.Max(m-1, n-1)+1];
+            System.Diagnostics.Debug.Assert(m>=0 & n>=0, "Error in LUDecomposition: incorrect function arguments");
+            
+            //
+            // Quick return if possible
+            //
+            if( m==0 | n==0 )
+            {
+                return;
+            }
+            for(j=0; j<=Math.Min(m-1, n-1); j++)
+            {
+                
+                //
+                // Find pivot and test for singularity.
+                //
+                jp = j;
+                for(i=j+1; i<=m-1; i++)
+                {
+                    if( (double)(Math.Abs(a[i,j]))>(double)(Math.Abs(a[jp,j])) )
+                    {
+                        jp = i;
+                    }
+                }
+                pivots[j] = jp;
+                if( (double)(a[jp,j])!=(double)(0) )
+                {
+                    
+                    //
+                    //Apply the interchange to rows
+                    //
+                    if( jp!=j )
+                    {
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            t1[i_] = a[j,i_];
+                        }
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            a[j,i_] = a[jp,i_];
+                        }
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            a[jp,i_] = t1[i_];
+                        }
+                    }
+                    
+                    //
+                    //Compute elements J+1:M of J-th column.
+                    //
+                    if( j<m )
+                    {
+                        jp = j+1;
+                        s = 1/a[j,j];
+                        for(i_=jp; i_<=m-1;i_++)
+                        {
+                            a[i_,j] = s*a[i_,j];
+                        }
+                    }
+                }
+                if( j<Math.Min(m, n)-1 )
+                {
+                    
+                    //
+                    //Update trailing submatrix.
+                    //
+                    jp = j+1;
+                    for(i=j+1; i<=m-1; i++)
+                    {
+                        s = a[i,j];
+                        for(i_=jp; i_<=n-1;i_++)
+                        {
+                            a[i,i_] = a[i,i_] - s*a[j,i_];
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mannwhitneyu.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mannwhitneyu.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mannwhitneyu.cs	(revision 2645)
@@ -0,0 +1,4386 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class mannwhitneyu
+    {
+        /*************************************************************************
+        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].
+
+          -- ALGLIB --
+             Copyright 09.04.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mannwhitneyutest(ref double[] x,
+            int n,
+            ref double[] y,
+            int m,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            int tmpi = 0;
+            int ns = 0;
+            double[] r = new double[0];
+            int[] c = new int[0];
+            double u = 0;
+            double p = 0;
+            double mp = 0;
+            double s = 0;
+            double sigma = 0;
+            double mu = 0;
+            int tiecount = 0;
+            int[] tiesize = new int[0];
+
+            
+            //
+            // Prepare
+            //
+            if( n<=4 | m<=4 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            ns = n+m;
+            r = new double[ns-1+1];
+            c = new int[ns-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                r[i] = x[i];
+                c[i] = 0;
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                r[n+i] = y[i];
+                c[n+i] = 1;
+            }
+            
+            //
+            // sort {R, C}
+            //
+            if( ns!=1 )
+            {
+                i = 2;
+                do
+                {
+                    t = i;
+                    while( t!=1 )
+                    {
+                        k = t/2;
+                        if( (double)(r[k-1])>=(double)(r[t-1]) )
+                        {
+                            t = 1;
+                        }
+                        else
+                        {
+                            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 = i+1;
+                }
+                while( i<=ns );
+                i = ns-1;
+                do
+                {
+                    tmp = r[i];
+                    r[i] = r[0];
+                    r[0] = tmp;
+                    tmpi = c[i];
+                    c[i] = c[0];
+                    c[0] = tmpi;
+                    t = 1;
+                    while( t!=0 )
+                    {
+                        k = 2*t;
+                        if( k>i )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            if( k<i )
+                            {
+                                if( (double)(r[k])>(double)(r[k-1]) )
+                                {
+                                    k = k+1;
+                                }
+                            }
+                            if( (double)(r[t-1])>=(double)(r[k-1]) )
+                            {
+                                t = 0;
+                            }
+                            else
+                            {
+                                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 = i-1;
+                }
+                while( i>=1 );
+            }
+            
+            //
+            // compute tied ranks
+            //
+            i = 0;
+            tiecount = 0;
+            tiesize = new int[ns-1+1];
+            while( i<=ns-1 )
+            {
+                j = i+1;
+                while( j<=ns-1 )
+                {
+                    if( (double)(r[j])!=(double)(r[i]) )
+                    {
+                        break;
+                    }
+                    j = j+1;
+                }
+                for(k=i; k<=j-1; k++)
+                {
+                    r[k] = 1+((double)(i+j-1))/(double)(2);
+                }
+                tiesize[tiecount] = j-i;
+                tiecount = tiecount+1;
+                i = j;
+            }
+            
+            //
+            // Compute U
+            //
+            u = 0;
+            for(i=0; i<=ns-1; i++)
+            {
+                if( c[i]==0 )
+                {
+                    u = u+r[i];
+                }
+            }
+            u = n*m+n*(n+1)/2-u;
+            
+            //
+            // Result
+            //
+            mu = (double)(n*m)/(double)(2);
+            tmp = ns*(AP.Math.Sqr(ns)-1)/12;
+            for(i=0; i<=tiecount-1; i++)
+            {
+                tmp = tmp-tiesize[i]*(AP.Math.Sqr(tiesize[i])-1)/12;
+            }
+            sigma = Math.Sqrt((double)(m*n)/(double)(ns)/(ns-1)*tmp);
+            s = (u-mu)/sigma;
+            if( (double)(s)<=(double)(0) )
+            {
+                p = Math.Exp(usigma(-((u-mu)/sigma), n, m));
+                mp = 1-Math.Exp(usigma(-((u-1-mu)/sigma), n, m));
+            }
+            else
+            {
+                mp = Math.Exp(usigma((u-mu)/sigma, n, m));
+                p = 1-Math.Exp(usigma((u+1-mu)/sigma, n, m));
+            }
+            bothtails = Math.Max(2*Math.Min(p, mp), 1.0E-4);
+            lefttail = Math.Max(mp, 1.0E-4);
+            righttail = Math.Max(p, 1.0E-4);
+        }
+
+
+        /*************************************************************************
+        Sequential Chebyshev interpolation.
+        *************************************************************************/
+        private static void ucheb(double x,
+            double c,
+            ref double tj,
+            ref double tj1,
+            ref double r)
+        {
+            double t = 0;
+
+            r = r+c*tj;
+            t = 2*x*tj1-tj;
+            tj = tj1;
+            tj1 = t;
+        }
+
+
+        /*************************************************************************
+        Three-point polynomial interpolation.
+        *************************************************************************/
+        private static double uninterpolate(double p1,
+            double p2,
+            double p3,
+            int n)
+        {
+            double result = 0;
+            double t1 = 0;
+            double t2 = 0;
+            double t3 = 0;
+            double t = 0;
+            double p12 = 0;
+            double p23 = 0;
+
+            t1 = 1.0/15.0;
+            t2 = 1.0/30.0;
+            t3 = 1.0/100.0;
+            t = 1.0/n;
+            p12 = ((t-t2)*p1+(t1-t)*p2)/(t1-t2);
+            p23 = ((t-t3)*p2+(t2-t)*p3)/(t2-t3);
+            result = ((t-t3)*p12+(t1-t)*p23)/(t1-t3);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(0, N1, N2)
+        *************************************************************************/
+        private static double usigma000(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-6.76984e-01, -6.83700e-01, -6.89873e-01, n2);
+            p2 = uninterpolate(-6.83700e-01, -6.87311e-01, -6.90957e-01, n2);
+            p3 = uninterpolate(-6.89873e-01, -6.90957e-01, -6.92175e-01, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(0.75, N1, N2)
+        *************************************************************************/
+        private static double usigma075(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-1.44500e+00, -1.45906e+00, -1.47063e+00, n2);
+            p2 = uninterpolate(-1.45906e+00, -1.46856e+00, -1.47644e+00, n2);
+            p3 = uninterpolate(-1.47063e+00, -1.47644e+00, -1.48100e+00, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(1.5, N1, N2)
+        *************************************************************************/
+        private static double usigma150(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-2.65380e+00, -2.67352e+00, -2.69011e+00, n2);
+            p2 = uninterpolate(-2.67352e+00, -2.68591e+00, -2.69659e+00, n2);
+            p3 = uninterpolate(-2.69011e+00, -2.69659e+00, -2.70192e+00, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(2.25, N1, N2)
+        *************************************************************************/
+        private static double usigma225(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-4.41465e+00, -4.42260e+00, -4.43702e+00, n2);
+            p2 = uninterpolate(-4.42260e+00, -4.41639e+00, -4.41928e+00, n2);
+            p3 = uninterpolate(-4.43702e+00, -4.41928e+00, -4.41030e+00, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(3.0, N1, N2)
+        *************************************************************************/
+        private static double usigma300(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-6.89839e+00, -6.83477e+00, -6.82340e+00, n2);
+            p2 = uninterpolate(-6.83477e+00, -6.74559e+00, -6.71117e+00, n2);
+            p3 = uninterpolate(-6.82340e+00, -6.71117e+00, -6.64929e+00, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(3.33, N1, N2)
+        *************************************************************************/
+        private static double usigma333(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-8.31272e+00, -8.17096e+00, -8.13125e+00, n2);
+            p2 = uninterpolate(-8.17096e+00, -8.00156e+00, -7.93245e+00, n2);
+            p3 = uninterpolate(-8.13125e+00, -7.93245e+00, -7.82502e+00, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(3.66, N1, N2)
+        *************************************************************************/
+        private static double usigma367(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-9.98837e+00, -9.70844e+00, -9.62087e+00, n2);
+            p2 = uninterpolate(-9.70844e+00, -9.41156e+00, -9.28998e+00, n2);
+            p3 = uninterpolate(-9.62087e+00, -9.28998e+00, -9.11686e+00, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(4.0, N1, N2)
+        *************************************************************************/
+        private static double usigma400(int n1,
+            int n2)
+        {
+            double result = 0;
+            double p1 = 0;
+            double p2 = 0;
+            double p3 = 0;
+
+            p1 = uninterpolate(-1.20250e+01, -1.14911e+01, -1.13231e+01, n2);
+            p2 = uninterpolate(-1.14911e+01, -1.09927e+01, -1.07937e+01, n2);
+            p3 = uninterpolate(-1.13231e+01, -1.07937e+01, -1.05285e+01, n2);
+            result = uninterpolate(p1, p2, p3, n1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 5)
+        *************************************************************************/
+        private static double utbln5n5(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/2.611165e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -2.596264e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.412086e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.858542e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.614282e-02, ref tj, ref tj1, ref result);
+            ucheb(x, 3.372686e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.524731e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.435331e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.284665e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.184141e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.298360e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 7.447272e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.938769e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.276205e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.138481e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.684625e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.558104e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 6)
+        *************************************************************************/
+        private static double utbln5n6(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/2.738613e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -2.810459e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.684429e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -5.712858e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.009324e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.644391e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 6.034173e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.953498e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.279293e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.563485e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.971952e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.506309e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.541406e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.283205e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.016347e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.221626e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.286752e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 7)
+        *************************************************************************/
+        private static double utbln5n7(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/2.841993e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -2.994677e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.923264e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -6.506190e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.054280e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.794587e-02, ref tj, ref tj1, ref result);
+            ucheb(x, 1.726290e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.534180e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.517845e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.904428e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.882443e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.482988e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.114875e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.515082e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.996056e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.293581e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.349444e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 8)
+        *************************************************************************/
+        private static double utbln5n8(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/2.927700e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.155727e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.135078e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -7.247203e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.309697e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.993725e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.567219e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.383704e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.002188e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.487322e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.443899e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.688270e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.600339e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.874948e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.811593e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.072353e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.659457e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 9)
+        *************************************************************************/
+        private static double utbln5n9(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.298162e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.325016e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -7.939852e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.563029e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.222652e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.195200e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.445665e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.204792e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.775217e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.527781e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.221948e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.242968e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.607959e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.771285e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 6.694026e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.481190e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 10)
+        *************************************************************************/
+        private static double utbln5n10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.061862e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.425360e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.496710e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -8.587658e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.812005e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.427637e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.515702e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.406867e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.796295e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.237591e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.654249e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.181165e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.011665e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.417927e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.534880e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.791255e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.871512e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 11)
+        *************************************************************************/
+        private static double utbln5n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.115427e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.539959e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.652998e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.196503e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.054363e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.618848e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.109411e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.786668e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.215648e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.484220e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.935991e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.396191e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.894177e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.206979e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.519055e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.210326e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.189679e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 12)
+        *************************************************************************/
+        private static double utbln5n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.162278e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.644007e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.796173e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.771177e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.290043e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.794686e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.702110e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.185959e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.416259e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.592056e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.201530e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.754365e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.978945e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.012032e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.304579e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.100378e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.728269e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 13)
+        *************************************************************************/
+        private static double utbln5n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.203616e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.739120e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.928117e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.031605e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.519403e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.962648e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.292183e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.809293e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.465156e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.456278e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.446055e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.109490e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.218256e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.941479e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.058603e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.824402e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.830947e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 14)
+        *************************************************************************/
+        private static double utbln5n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.240370e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.826559e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.050370e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.083408e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.743164e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.012030e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.884686e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.059656e-02, ref tj, ref tj1, ref result);
+            ucheb(x, 1.327521e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.134026e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.584201e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.440618e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.524133e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.990007e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.887334e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.534977e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.705395e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 15)
+        *************************************************************************/
+        private static double utbln5n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.851572e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.082033e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.095983e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.814595e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.073148e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.420213e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.517175e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.344180e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.371393e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.711443e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.228569e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.683483e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.267112e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.156044e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 9.131316e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.301023e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 16)
+        *************************************************************************/
+        private static double utbln5n16(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.852210e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.077482e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.091186e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.797282e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.084994e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.667054e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.843909e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.456732e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.039830e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.723508e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.940608e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.478285e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.649144e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.237703e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.707410e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.874293e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 17)
+        *************************************************************************/
+        private static double utbln5n17(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.851752e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.071259e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.084700e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.758898e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.073846e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.684838e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.964936e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.782442e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.956362e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.984727e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.196936e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.558262e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.690746e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.364855e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.401006e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.546748e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 18)
+        *************************************************************************/
+        private static double utbln5n18(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.850840e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.064799e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.077651e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.712659e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.049217e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.571333e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.929809e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.752044e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.949464e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.896101e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.614460e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.384357e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.489113e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -6.445725e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.945636e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.424653e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 19)
+        *************************************************************************/
+        private static double utbln5n19(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.850027e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.059159e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.071106e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.669960e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.022780e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.442555e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.851335e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.433865e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.514465e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.332989e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 8.606099e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.341945e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.402164e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.039761e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.512831e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.284427e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 20)
+        *************************************************************************/
+        private static double utbln5n20(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.849651e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.054729e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.065747e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.636243e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.003234e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.372789e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.831551e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.763090e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.830626e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.122384e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 8.108328e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.557983e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.945666e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.965696e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.493236e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.162591e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 21)
+        *************************************************************************/
+        private static double utbln5n21(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.849649e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.051155e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.061430e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.608869e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.902788e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.346562e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.874709e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.682887e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.026206e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.534551e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.990575e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.713334e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 9.737011e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.304571e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.133110e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.123457e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 22)
+        *************************************************************************/
+        private static double utbln5n22(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.849598e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.047605e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.057264e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.579513e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.749602e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.275137e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.881768e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.177374e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.981056e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.696290e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.886803e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.085378e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.675242e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.426367e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.039613e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.662378e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 23)
+        *************************************************************************/
+        private static double utbln5n23(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.849269e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.043761e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.052735e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.544683e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.517503e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.112082e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.782070e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.549483e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.747329e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.694263e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.147141e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.526209e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.039173e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.235615e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.656546e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.014423e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 24)
+        *************************************************************************/
+        private static double utbln5n24(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.848925e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.040178e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.048355e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.510198e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.261134e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.915864e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.627423e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.307345e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.732992e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.869652e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.494176e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.047533e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.178439e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.424171e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.829195e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.840810e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 25)
+        *************************************************************************/
+        private static double utbln5n25(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.848937e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.037512e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.044866e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.483269e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.063682e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.767778e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.508540e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.332756e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.881511e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.124041e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.368456e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.930499e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.779630e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.029528e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.658678e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.289695e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 26)
+        *************************************************************************/
+        private static double utbln5n26(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.849416e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.035915e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.042493e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.466021e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.956432e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.698914e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.465689e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.035254e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.674614e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.492734e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.014021e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.944953e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.255750e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.075841e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.989330e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.134862e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 27)
+        *************************************************************************/
+        private static double utbln5n27(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.850070e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.034815e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.040650e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.453117e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.886426e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.661702e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.452346e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.002476e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.720126e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.001400e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.729826e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.740640e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.206333e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.366093e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.193471e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.804091e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 28)
+        *************************************************************************/
+        private static double utbln5n28(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.850668e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.033786e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.038853e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.440281e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.806020e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.612883e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.420436e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.787982e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.535230e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.263121e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.849609e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.863967e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.391610e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.720294e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.952273e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.901413e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 29)
+        *************************************************************************/
+        private static double utbln5n29(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.851217e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.032834e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.037113e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.427762e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.719146e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.557172e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.375498e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.452033e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.187516e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.916936e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.065533e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.067301e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.615824e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.432244e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.417795e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.710038e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 30)
+        *************************************************************************/
+        private static double utbln5n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.851845e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.032148e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.035679e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.417758e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.655330e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.522132e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.352106e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.326911e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.064969e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.813321e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.683881e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 2.813346e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.627085e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.832107e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.519336e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.888530e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5, 100)
+        *************************************************************************/
+        private static double utbln5n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.250000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.877940e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.039324e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.022243e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.305825e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.960119e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.112000e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.138868e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.418164e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.174520e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.489617e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.878301e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.302233e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.054113e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 2.458862e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -4.186591e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.623412e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 6)
+        *************************************************************************/
+        private static double utbln6n6(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/2.882307e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.054075e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.998804e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -6.681518e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.067578e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.709435e-02, ref tj, ref tj1, ref result);
+            ucheb(x, 9.952661e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.641700e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.304572e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.336275e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.770385e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.401891e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.246148e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.442663e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.502866e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.105855e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.739371e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 7)
+        *************************************************************************/
+        private static double utbln6n7(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.265287e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.274613e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -7.582352e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.334293e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.915502e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.108091e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.546701e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.298827e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.891501e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.313717e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.989501e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.914594e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.062372e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.158841e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.596443e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.185662e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 8)
+        *************************************************************************/
+        private static double utbln6n8(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.098387e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.450954e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.520462e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -8.420299e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.604853e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.165840e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.008756e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.723402e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.843521e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.883405e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.720980e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.301709e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.948034e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.776243e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.623736e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.742068e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -9.796927e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 9)
+        *************************************************************************/
+        private static double utbln6n9(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.181981e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.616113e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.741650e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.204487e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.873068e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.446794e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.632286e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.266481e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.280067e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.780687e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.480242e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.592200e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.581019e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.264231e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.347174e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.167535e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.092185e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 10)
+        *************************************************************************/
+        private static double utbln6n10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.253957e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.764382e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.942366e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.939896e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.137812e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.720270e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.281070e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.901060e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.824937e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.802812e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.258132e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.233536e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.085530e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.212151e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.001329e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.226048e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.035298e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 11)
+        *************************************************************************/
+        private static double utbln6n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.316625e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.898597e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.125710e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.063297e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.396852e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.990126e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.927977e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.726500e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.858745e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.654590e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.217736e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.989770e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.768493e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.924364e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.140215e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.647914e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.924802e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 12)
+        *************************************************************************/
+        private static double utbln6n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.371709e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.020941e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.294250e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.128842e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.650389e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.248611e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.578510e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.162852e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.746982e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.454209e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.128042e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.936650e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.530794e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.665192e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.994144e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.662249e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.368541e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 13)
+        *************************************************************************/
+        private static double utbln6n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.420526e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.133167e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.450016e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.191088e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.898220e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.050249e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.226901e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.471113e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.007470e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.049420e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.059074e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.881249e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.452780e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.441805e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.787493e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.483957e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.481590e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 14)
+        *************************************************************************/
+        private static double utbln6n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.450000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.201268e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.542568e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.226965e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.046029e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.136657e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.786757e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.843748e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.588022e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.253029e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.667188e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.788330e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.474545e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.540494e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.951188e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.863323e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.220904e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 15)
+        *************************************************************************/
+        private static double utbln6n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.450000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.195689e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.526567e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.213617e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.975035e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.118480e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.859142e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.083312e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.298720e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.766708e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.026356e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.093113e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.135168e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.136376e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.190870e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.435972e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.413129e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 30)
+        *************************************************************************/
+        private static double utbln6n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.450000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.166269e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.427399e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.118239e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.360847e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.745885e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.025041e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.187179e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.432089e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.408451e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.388774e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.795560e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.304136e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.258516e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.180236e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -4.388679e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 4.836027e-06, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6, 100)
+        *************************************************************************/
+        private static double utbln6n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.450000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.181350e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.417919e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.094201e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.195883e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.818937e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.514202e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.125047e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.022148e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.284181e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.157766e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.023752e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.127985e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.221690e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.516179e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 9.501398e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 9.380220e-06, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 7)
+        *************************************************************************/
+        private static double utbln7n7(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.130495e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.501264e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.584790e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -8.577311e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.617002e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.145186e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.023462e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.408251e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.626515e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.072492e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.722926e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.095445e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.842602e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.751427e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.008927e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -9.892431e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.772386e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 8)
+        *************************************************************************/
+        private static double utbln7n8(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.240370e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.709965e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -3.862154e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.504541e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.900195e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.439995e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.678028e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.485540e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.437047e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.440092e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.114227e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.516569e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.829457e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.787550e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.761866e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.991911e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.533481e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 9)
+        *************************************************************************/
+        private static double utbln7n9(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.334314e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.896550e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.112671e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.037277e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.181695e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.765190e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.360116e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.695960e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.780578e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.963843e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.616148e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.852104e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.390744e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.014041e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.888101e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.467474e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.004611e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 10)
+        *************************************************************************/
+        private static double utbln7n10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.415650e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.064844e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.340749e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.118888e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.459730e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.097781e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.057688e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.097406e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.209262e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.065641e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.196677e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.313994e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.827157e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.822284e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.389090e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.340850e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.395172e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 11)
+        *************************************************************************/
+        private static double utbln7n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.486817e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.217795e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.549783e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.195905e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.733093e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.428447e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.760093e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.431676e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.717152e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.032199e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.832423e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.905979e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.302799e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.464371e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.456211e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.736244e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.140712e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 12)
+        *************************************************************************/
+        private static double utbln7n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.500000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.235822e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.564100e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.190813e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.686546e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.395083e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.967359e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.747096e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.304144e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.903198e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.134906e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.175035e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.266224e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.892931e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.604706e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 9.070459e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.427010e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 13)
+        *************************************************************************/
+        private static double utbln7n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.500000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.222204e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.532300e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.164642e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.523768e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.531984e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.467857e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.483804e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.524136e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.077740e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.745218e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.602085e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.828831e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.994070e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.873879e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.341937e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.706444e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 14)
+        *************************************************************************/
+        private static double utbln7n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.500000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.211763e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.507542e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.143640e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.395755e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.808020e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.044259e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.182308e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.057325e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.724255e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 8.303900e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.113148e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.102514e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.559442e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.634986e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -8.776476e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.054489e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 15)
+        *************************************************************************/
+        private static double utbln7n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.500000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.204898e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.489960e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.129172e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.316741e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.506107e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.983676e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.258013e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.262515e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.984156e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.912108e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 8.974023e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 6.056195e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.090842e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.232620e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.816339e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.020421e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 30)
+        *************************************************************************/
+        private static double utbln7n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.500000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.176536e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.398705e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.045481e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.821982e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.962304e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.698132e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.062667e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.282353e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.014836e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.035683e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.004137e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 3.801453e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.920705e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.518735e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.821501e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.801008e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7, 100)
+        *************************************************************************/
+        private static double utbln7n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.500000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.188337e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.386949e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.022834e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.686517e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.323516e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.399392e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.644333e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.617044e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.031396e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.792066e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 2.675457e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.673416e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -6.258552e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -8.174214e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -3.073644e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.349958e-06, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 8)
+        *************************************************************************/
+        private static double utbln8n8(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.360672e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -3.940217e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.168913e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.051485e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.195325e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.775196e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.385506e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.244902e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.525632e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.771275e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.332874e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.079599e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.882551e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.407944e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.769844e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.062433e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 5.872535e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 9)
+        *************************************************************************/
+        private static double utbln8n9(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.464102e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.147004e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.446939e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.146155e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.488561e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.144561e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.116917e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.205667e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.515661e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.618616e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.599011e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.457324e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.482917e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.488267e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.469823e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.957591e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 8.058326e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 10)
+        *************************************************************************/
+        private static double utbln8n10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.554093e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.334282e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.700860e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.235253e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.778489e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.527324e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.862885e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.589781e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.507355e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.717526e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 9.215726e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.848696e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.918854e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.219614e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.753761e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.573688e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.602177e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 11)
+        *************************************************************************/
+        private static double utbln8n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.421882e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.812457e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.266153e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.849344e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.971527e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.258944e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.944820e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.894685e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.031836e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.514330e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.351660e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 6.206748e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.492600e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.005338e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.780099e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.673599e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 12)
+        *************************************************************************/
+        private static double utbln8n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.398211e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.762214e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.226296e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.603837e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.643223e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.502438e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.544574e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.647734e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.442259e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.011484e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.384758e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.998259e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.659985e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.331046e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.638478e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.056785e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 13)
+        *************************************************************************/
+        private static double utbln8n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.380670e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.724511e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.195851e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.420511e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.609928e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.893999e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.115919e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.291410e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.339664e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.801548e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.534710e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.793250e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.806718e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.384624e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.120582e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.936453e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 14)
+        *************************************************************************/
+        private static double utbln8n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.368494e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.697171e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.174440e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.300621e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.087393e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.685826e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.085254e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.525658e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.966647e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.453388e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.826066e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.501958e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.336297e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.251972e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.118456e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -9.415959e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 15)
+        *************************************************************************/
+        private static double utbln8n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.358397e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.674485e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.155941e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.195780e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.544830e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.426183e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.309902e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.650956e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.068874e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.538544e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 8.192525e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.073905e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.079673e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 9.423572e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 6.579647e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.765904e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 30)
+        *************************************************************************/
+        private static double utbln8n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.318823e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.567159e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.064864e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.688413e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.153712e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.309389e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.226861e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.523815e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.780987e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.166866e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.922431e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.466397e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -5.690036e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.008185e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -9.271903e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -7.534751e-06, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8, 100)
+        *************************************************************************/
+        private static double utbln8n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.600000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.324531e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.547071e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.038129e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.541549e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.525605e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.044992e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.085713e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.017871e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.459226e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.092064e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.024349e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 7.366347e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 6.385637e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 8.321722e-08, ref tj, ref tj1, ref result);
+            ucheb(x, -1.439286e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -3.058079e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 9)
+        *************************************************************************/
+        private static double utbln9n9(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.576237e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.372857e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.750859e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.248233e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.792868e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.559372e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.894941e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.643256e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.091370e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.285034e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 6.112997e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.806229e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.150741e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 4.509825e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 3.891051e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.485013e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.343653e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 10)
+        *************************************************************************/
+        private static double utbln9n10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.516726e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.939333e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.305046e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.935326e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.029141e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.420592e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.053140e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.065930e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.523581e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.544888e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.813741e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.510631e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.536057e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.833815e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 2.189692e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 1.615050e-03, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 11)
+        *************************************************************************/
+        private static double utbln9n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.481308e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.867483e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.249072e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.591790e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.400128e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.341992e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.463680e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.487211e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.671196e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.343472e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.544146e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.802335e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.117084e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.217443e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.858766e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.193687e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 12)
+        *************************************************************************/
+        private static double utbln9n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.456776e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.817037e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.209788e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.362108e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.171356e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.661557e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.026141e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.361908e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.093885e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.298389e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.663603e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.768522e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.579015e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.868677e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.440652e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.523037e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 13)
+        *************************************************************************/
+        private static double utbln9n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.438840e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.779308e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.180614e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.196489e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.346621e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.234857e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.796211e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.575715e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.525647e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.964651e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.275235e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.299124e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.397416e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.295781e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.237619e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 7.269692e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 14)
+        *************************************************************************/
+        private static double utbln9n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.425981e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.751545e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.159543e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.086570e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.917446e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.120112e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.175519e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.515473e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.727772e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.070629e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.677569e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.876953e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.233502e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.508182e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.120389e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.847212e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 15)
+        *************************************************************************/
+        private static double utbln9n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.414952e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.727612e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.140634e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.981231e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.382635e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.853575e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.571051e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.567625e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.214197e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.448700e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.712669e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.015050e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.438610e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 6.301363e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.309386e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.164772e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 30)
+        *************************************************************************/
+        private static double utbln9n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.370720e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.615712e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.050023e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.504775e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.318265e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.646826e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.741492e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.735360e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.966911e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.100738e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.348991e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.527687e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.917286e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 3.397466e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -2.360175e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -9.892252e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9, 100)
+        *************************************************************************/
+        private static double utbln9n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.372506e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.590966e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.021758e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.359849e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.755519e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.533166e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.936659e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.634913e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.730053e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.791845e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.030682e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -5.228663e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 8.631175e-07, ref tj, ref tj1, ref result);
+            ucheb(x, 1.636749e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 4.404599e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -2.789872e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 10)
+        *************************************************************************/
+        private static double utbln10n10(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.468831e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.844398e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.231728e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.486073e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -7.781321e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.971425e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.215371e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.828451e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.419872e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.430165e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.740363e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.049211e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.269371e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.211393e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.232314e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.016081e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 11)
+        *************************************************************************/
+        private static double utbln10n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.437998e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.782296e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.184732e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.219585e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.457012e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.296008e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.481501e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.527940e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.953426e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.563840e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.574403e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.535775e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.338037e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.002654e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.852676e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.318132e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 12)
+        *************************************************************************/
+        private static double utbln10n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.416082e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.737458e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.150952e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.036884e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.609030e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.908684e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.439666e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.162647e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.451601e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.148757e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.803981e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.731621e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.346903e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.013151e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.956148e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.438381e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 13)
+        *************************************************************************/
+        private static double utbln10n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.399480e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.702863e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.124829e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.897428e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.979802e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.634368e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.180461e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.484926e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.864376e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 4.186576e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.886925e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.836828e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.074756e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.209547e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.883266e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.380143e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 14)
+        *************************************************************************/
+        private static double utbln10n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.386924e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.676124e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.104740e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.793826e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.558886e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.492462e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.052903e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.917782e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.878696e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.576046e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.764551e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -9.288778e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -4.757658e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.299101e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -9.265197e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.384503e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 15)
+        *************************************************************************/
+        private static double utbln10n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.376846e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.654247e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.088083e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.705945e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.169677e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.317213e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.264836e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.548024e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.633910e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.505621e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.658588e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.320254e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.175277e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.122317e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.675688e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.661363e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 30)
+        *************************************************************************/
+        private static double utbln10n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.333977e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.548099e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.004444e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.291014e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.523674e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.828211e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.716917e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -4.894256e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.433371e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.522675e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.764192e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -9.140235e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -5.629230e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -3.541895e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.944946e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.726360e-06, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10, 100)
+        *************************************************************************/
+        private static double utbln10n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.650000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.334008e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.522316e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.769627e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.158110e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.053650e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.242235e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.173571e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.033661e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.824732e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.084420e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -6.610036e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.728155e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.217130e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.340966e-07, ref tj, ref tj1, ref result);
+            ucheb(x, 2.001235e-07, ref tj, ref tj1, ref result);
+            ucheb(x, 1.694052e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 11)
+        *************************************************************************/
+        private static double utbln11n11(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.519760e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.880694e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.200698e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -2.174092e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -6.072304e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.054773e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -6.506613e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.813942e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.223644e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.417416e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.499166e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.194332e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 7.369096e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.968590e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.630532e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.061000e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 12)
+        *************************************************************************/
+        private static double utbln11n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.495790e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.832622e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.165420e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.987306e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -5.265621e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.723537e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.347406e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.353464e-03, ref tj, ref tj1, ref result);
+            ucheb(x, 6.613369e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 5.102522e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 5.237709e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.665652e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.626903e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.167518e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -8.564455e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.047320e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 13)
+        *************************************************************************/
+        private static double utbln11n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.477880e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.796242e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.138769e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.851739e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.722104e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.548304e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.176683e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.817895e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.842451e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.935870e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 8.421777e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.238831e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 8.867026e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.458255e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.306259e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -8.961487e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 14)
+        *************************************************************************/
+        private static double utbln11n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.463683e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.766969e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.117082e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.739574e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.238865e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.350306e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.425871e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.640172e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.660633e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.879883e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.349658e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.271795e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.304544e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.024201e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.816867e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -4.596787e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 15)
+        *************************************************************************/
+        private static double utbln11n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.452526e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.743570e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.099705e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.650612e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.858285e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.187036e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.689241e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.294360e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.072623e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.278008e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.322382e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -9.131558e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -7.305669e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -6.825627e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -5.332689e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -6.120973e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 30)
+        *************************************************************************/
+        private static double utbln11n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.402621e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.627440e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.011333e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.224126e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.232856e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -5.859347e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.377381e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.756709e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.033230e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.875472e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -8.608399e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -3.102943e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.740693e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.343139e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -9.196878e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -6.658062e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11, 100)
+        *************************************************************************/
+        private static double utbln11n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.398795e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.596486e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.814761e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.085187e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.766529e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.379425e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.986351e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.214705e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.360075e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.260869e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.033307e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -7.727087e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -3.393883e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -2.242989e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -1.111928e-07, ref tj, ref tj1, ref result);
+            ucheb(x, 3.898823e-09, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12, 12)
+        *************************************************************************/
+        private static double utbln12n12(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.472616e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.786627e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.132099e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.817523e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.570179e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.479511e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.799492e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.565350e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.530139e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.380132e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.242761e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.576269e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 3.018771e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.933911e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 9.002799e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.022048e-06, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12, 13)
+        *************************************************************************/
+        private static double utbln12n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.454800e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.750794e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.105988e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.684754e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -4.011826e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.262579e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.044492e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.478741e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.322165e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.621104e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 4.068753e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.468396e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.056235e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 2.327375e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.914877e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 1.784191e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12, 14)
+        *************************************************************************/
+        private static double utbln12n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.440910e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.722404e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.085254e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.579439e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.563738e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.066730e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.129346e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.014531e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.129679e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.000909e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.996174e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 6.377924e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 8.936304e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.051098e-04, ref tj, ref tj1, ref result);
+            ucheb(x, 9.025820e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 8.730585e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12, 15)
+        *************************************************************************/
+        private static double utbln12n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.430123e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.700008e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.068971e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.499725e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.250897e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.473145e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.680008e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.483350e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.766992e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -9.891081e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -4.015140e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.977756e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -8.707414e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 1.114786e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 6.238865e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 1.381445e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12, 30)
+        *************************************************************************/
+        private static double utbln12n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.380023e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.585782e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.838583e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.103394e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.834015e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.635212e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.948212e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.574169e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.747980e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.833672e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -5.722433e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.181038e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.206473e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -9.716003e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -7.476434e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -7.217700e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12, 100)
+        *************************************************************************/
+        private static double utbln12n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.700000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.374567e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.553481e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.541334e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.701907e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.414757e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.404103e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.234388e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.453762e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.311060e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -7.317501e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.713888e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -3.309583e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -4.019804e-08, ref tj, ref tj1, ref result);
+            ucheb(x, 1.224829e-09, ref tj, ref tj1, ref result);
+            ucheb(x, -1.349019e-08, ref tj, ref tj1, ref result);
+            ucheb(x, -1.893302e-08, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 13, 13)
+        *************************************************************************/
+        private static double utbln13n13(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.541046e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.859047e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.130164e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.689719e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.950693e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.231455e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.976550e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -1.538455e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.245603e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -4.142647e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.831434e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.032483e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.488405e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.156927e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.949279e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -7.532700e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 13, 14)
+        *************************************************************************/
+        private static double utbln13n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.525655e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.828341e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.108110e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.579552e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.488307e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.032328e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.988741e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -9.766394e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.388950e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.338179e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.133440e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.023518e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.110570e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 4.202332e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 1.056132e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.536323e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 13, 15)
+        *************************************************************************/
+        private static double utbln13n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.513585e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.803952e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.090686e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.495310e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.160314e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -9.073124e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.480313e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.478239e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.140914e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.311541e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.677105e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 1.115464e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.578563e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 2.044604e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 1.888939e-05, ref tj, ref tj1, ref result);
+            ucheb(x, 2.395644e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 13, 30)
+        *************************************************************************/
+        private static double utbln13n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.455999e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.678434e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.995491e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.078100e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -1.705220e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -4.258739e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -8.671526e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.185458e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -5.507764e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.411446e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -4.044355e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.285765e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -5.345282e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -3.066940e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -1.962037e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -1.723644e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 13, 100)
+        *************************************************************************/
+        private static double utbln13n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.446787e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.640804e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.671552e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.364990e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.274444e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.047440e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -5.161439e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.171729e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.562171e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -5.359762e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -1.275494e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.747635e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -5.700292e-08, ref tj, ref tj1, ref result);
+            ucheb(x, -2.565559e-09, ref tj, ref tj1, ref result);
+            ucheb(x, 5.005396e-09, ref tj, ref tj1, ref result);
+            ucheb(x, 3.335794e-09, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 14, 14)
+        *************************************************************************/
+        private static double utbln14n14(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.510624e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.798584e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.087107e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.478532e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -3.098050e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -8.855986e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.409083e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -7.299536e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.176177e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -6.479417e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.812761e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -5.225872e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 4.516521e-07, ref tj, ref tj1, ref result);
+            ucheb(x, 6.730551e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 9.237563e-06, ref tj, ref tj1, ref result);
+            ucheb(x, 1.611820e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 14, 15)
+        *************************************************************************/
+        private static double utbln14n15(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.498681e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.774668e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.070267e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -1.399348e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -2.807239e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -7.845763e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -2.071773e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.261698e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -2.011695e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -7.305946e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.879295e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.999439e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.904438e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.944986e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.373908e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -2.140794e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 14, 30)
+        *************************************************************************/
+        private static double utbln14n30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.440378e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.649587e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.807829e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -9.989753e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.463646e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -3.586580e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -6.745917e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -1.635398e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -3.923172e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -9.446699e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -2.613892e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -8.214073e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -3.651683e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -2.272777e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -1.464988e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -1.109803e-07, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 14, 100)
+        *************************************************************************/
+        private static double utbln14n100(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/3.750000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            ucheb(x, -4.429701e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -4.610577e+00, ref tj, ref tj1, ref result);
+            ucheb(x, -9.482675e-01, ref tj, ref tj1, ref result);
+            ucheb(x, -8.605550e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -1.062151e-02, ref tj, ref tj1, ref result);
+            ucheb(x, -2.525154e-03, ref tj, ref tj1, ref result);
+            ucheb(x, -3.835983e-04, ref tj, ref tj1, ref result);
+            ucheb(x, -8.411440e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -1.744901e-05, ref tj, ref tj1, ref result);
+            ucheb(x, -3.318850e-06, ref tj, ref tj1, ref result);
+            ucheb(x, -7.692100e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -1.536270e-07, ref tj, ref tj1, ref result);
+            ucheb(x, -3.705888e-08, ref tj, ref tj1, ref result);
+            ucheb(x, -7.999599e-09, ref tj, ref tj1, ref result);
+            ucheb(x, -2.908395e-09, ref tj, ref tj1, ref result);
+            ucheb(x, 1.546923e-09, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, N1, N2)
+        *************************************************************************/
+        private static double usigma(double s,
+            int n1,
+            int n2)
+        {
+            double result = 0;
+            double f0 = 0;
+            double f1 = 0;
+            double f2 = 0;
+            double f3 = 0;
+            double f4 = 0;
+            double s0 = 0;
+            double s1 = 0;
+            double s2 = 0;
+            double s3 = 0;
+            double s4 = 0;
+
+            
+            //
+            // N1=5, N2 = 5, 6, 7, ...
+            //
+            if( Math.Min(n1, n2)==5 )
+            {
+                if( Math.Max(n1, n2)==5 )
+                {
+                    result = utbln5n5(s);
+                }
+                if( Math.Max(n1, n2)==6 )
+                {
+                    result = utbln5n6(s);
+                }
+                if( Math.Max(n1, n2)==7 )
+                {
+                    result = utbln5n7(s);
+                }
+                if( Math.Max(n1, n2)==8 )
+                {
+                    result = utbln5n8(s);
+                }
+                if( Math.Max(n1, n2)==9 )
+                {
+                    result = utbln5n9(s);
+                }
+                if( Math.Max(n1, n2)==10 )
+                {
+                    result = utbln5n10(s);
+                }
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln5n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln5n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln5n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln5n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln5n15(s);
+                }
+                if( Math.Max(n1, n2)==16 )
+                {
+                    result = utbln5n16(s);
+                }
+                if( Math.Max(n1, n2)==17 )
+                {
+                    result = utbln5n17(s);
+                }
+                if( Math.Max(n1, n2)==18 )
+                {
+                    result = utbln5n18(s);
+                }
+                if( Math.Max(n1, n2)==19 )
+                {
+                    result = utbln5n19(s);
+                }
+                if( Math.Max(n1, n2)==20 )
+                {
+                    result = utbln5n20(s);
+                }
+                if( Math.Max(n1, n2)==21 )
+                {
+                    result = utbln5n21(s);
+                }
+                if( Math.Max(n1, n2)==22 )
+                {
+                    result = utbln5n22(s);
+                }
+                if( Math.Max(n1, n2)==23 )
+                {
+                    result = utbln5n23(s);
+                }
+                if( Math.Max(n1, n2)==24 )
+                {
+                    result = utbln5n24(s);
+                }
+                if( Math.Max(n1, n2)==25 )
+                {
+                    result = utbln5n25(s);
+                }
+                if( Math.Max(n1, n2)==26 )
+                {
+                    result = utbln5n26(s);
+                }
+                if( Math.Max(n1, n2)==27 )
+                {
+                    result = utbln5n27(s);
+                }
+                if( Math.Max(n1, n2)==28 )
+                {
+                    result = utbln5n28(s);
+                }
+                if( Math.Max(n1, n2)==29 )
+                {
+                    result = utbln5n29(s);
+                }
+                if( Math.Max(n1, n2)>29 )
+                {
+                    f0 = utbln5n15(s);
+                    f1 = utbln5n30(s);
+                    f2 = utbln5n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=6, N2 = 6, 7, 8, ...
+            //
+            if( Math.Min(n1, n2)==6 )
+            {
+                if( Math.Max(n1, n2)==6 )
+                {
+                    result = utbln6n6(s);
+                }
+                if( Math.Max(n1, n2)==7 )
+                {
+                    result = utbln6n7(s);
+                }
+                if( Math.Max(n1, n2)==8 )
+                {
+                    result = utbln6n8(s);
+                }
+                if( Math.Max(n1, n2)==9 )
+                {
+                    result = utbln6n9(s);
+                }
+                if( Math.Max(n1, n2)==10 )
+                {
+                    result = utbln6n10(s);
+                }
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln6n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln6n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln6n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln6n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln6n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln6n15(s);
+                    f1 = utbln6n30(s);
+                    f2 = utbln6n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=7, N2 = 7, 8, ...
+            //
+            if( Math.Min(n1, n2)==7 )
+            {
+                if( Math.Max(n1, n2)==7 )
+                {
+                    result = utbln7n7(s);
+                }
+                if( Math.Max(n1, n2)==8 )
+                {
+                    result = utbln7n8(s);
+                }
+                if( Math.Max(n1, n2)==9 )
+                {
+                    result = utbln7n9(s);
+                }
+                if( Math.Max(n1, n2)==10 )
+                {
+                    result = utbln7n10(s);
+                }
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln7n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln7n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln7n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln7n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln7n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln7n15(s);
+                    f1 = utbln7n30(s);
+                    f2 = utbln7n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=8, N2 = 8, 9, 10, ...
+            //
+            if( Math.Min(n1, n2)==8 )
+            {
+                if( Math.Max(n1, n2)==8 )
+                {
+                    result = utbln8n8(s);
+                }
+                if( Math.Max(n1, n2)==9 )
+                {
+                    result = utbln8n9(s);
+                }
+                if( Math.Max(n1, n2)==10 )
+                {
+                    result = utbln8n10(s);
+                }
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln8n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln8n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln8n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln8n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln8n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln8n15(s);
+                    f1 = utbln8n30(s);
+                    f2 = utbln8n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=9, N2 = 9, 10, ...
+            //
+            if( Math.Min(n1, n2)==9 )
+            {
+                if( Math.Max(n1, n2)==9 )
+                {
+                    result = utbln9n9(s);
+                }
+                if( Math.Max(n1, n2)==10 )
+                {
+                    result = utbln9n10(s);
+                }
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln9n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln9n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln9n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln9n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln9n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln9n15(s);
+                    f1 = utbln9n30(s);
+                    f2 = utbln9n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=10, N2 = 10, 11, ...
+            //
+            if( Math.Min(n1, n2)==10 )
+            {
+                if( Math.Max(n1, n2)==10 )
+                {
+                    result = utbln10n10(s);
+                }
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln10n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln10n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln10n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln10n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln10n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln10n15(s);
+                    f1 = utbln10n30(s);
+                    f2 = utbln10n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=11, N2 = 11, 12, ...
+            //
+            if( Math.Min(n1, n2)==11 )
+            {
+                if( Math.Max(n1, n2)==11 )
+                {
+                    result = utbln11n11(s);
+                }
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln11n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln11n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln11n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln11n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln11n15(s);
+                    f1 = utbln11n30(s);
+                    f2 = utbln11n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=12, N2 = 12, 13, ...
+            //
+            if( Math.Min(n1, n2)==12 )
+            {
+                if( Math.Max(n1, n2)==12 )
+                {
+                    result = utbln12n12(s);
+                }
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln12n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln12n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln12n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln12n15(s);
+                    f1 = utbln12n30(s);
+                    f2 = utbln12n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=13, N2 = 13, 14, ...
+            //
+            if( Math.Min(n1, n2)==13 )
+            {
+                if( Math.Max(n1, n2)==13 )
+                {
+                    result = utbln13n13(s);
+                }
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln13n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln13n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln13n15(s);
+                    f1 = utbln13n30(s);
+                    f2 = utbln13n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1=14, N2 = 14, 15, ...
+            //
+            if( Math.Min(n1, n2)==14 )
+            {
+                if( Math.Max(n1, n2)==14 )
+                {
+                    result = utbln14n14(s);
+                }
+                if( Math.Max(n1, n2)==15 )
+                {
+                    result = utbln14n15(s);
+                }
+                if( Math.Max(n1, n2)>15 )
+                {
+                    f0 = utbln14n15(s);
+                    f1 = utbln14n30(s);
+                    f2 = utbln14n100(s);
+                    result = uninterpolate(f0, f1, f2, Math.Max(n1, n2));
+                }
+                return result;
+            }
+            
+            //
+            // N1 >= 15, N2 >= 15
+            //
+            if( (double)(s)>(double)(4) )
+            {
+                s = 4;
+            }
+            if( (double)(s)<(double)(3) )
+            {
+                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);
+                f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0);
+                f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0);
+                f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0);
+                f4 = ((s-s0)*f4-(s-s4)*f0)/(s4-s0);
+                f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1);
+                f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1);
+                f4 = ((s-s1)*f4-(s-s4)*f1)/(s4-s1);
+                f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2);
+                f4 = ((s-s2)*f4-(s-s4)*f2)/(s4-s2);
+                f4 = ((s-s3)*f4-(s-s4)*f3)/(s4-s3);
+                result = f4;
+            }
+            else
+            {
+                s0 = 3.000000e+00;
+                f0 = 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);
+                f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0);
+                f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0);
+                f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0);
+                f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1);
+                f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1);
+                f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2);
+                result = f3;
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/matgen.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/matgen.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/matgen.cs	(revision 2645)
@@ -0,0 +1,1050 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class matgen
+    {
+        /*************************************************************************
+        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]
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixrndorthogonal(int n,
+            ref double[,] a)
+        {
+            int i = 0;
+            int j = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "RMatrixRndOrthogonal: N<1!");
+            a = new double[n-1+1, n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        a[i,j] = 1;
+                    }
+                    else
+                    {
+                        a[i,j] = 0;
+                    }
+                }
+            }
+            rmatrixrndorthogonalfromtheright(ref a, n, n);
+        }
+
+
+        /*************************************************************************
+        Generation of random NxN matrix with given condition number and norm2(A)=1
+
+        INPUT PARAMETERS:
+            N   -   matrix size
+            C   -   condition number (in 2-norm)
+
+        OUTPUT PARAMETERS:
+            A   -   random matrix with norm2(A)=1 and cond(A)=C
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixrndcond(int n,
+            double c,
+            ref double[,] a)
+        {
+            int i = 0;
+            int j = 0;
+            double l1 = 0;
+            double l2 = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & (double)(c)>=(double)(1), "RMatrixRndCond: N<1 or C<1!");
+            a = new double[n-1+1, n-1+1];
+            if( n==1 )
+            {
+                
+                //
+                // special case
+                //
+                a[0,0] = 2*AP.Math.RandomInteger(2)-1;
+                return;
+            }
+            l1 = 0;
+            l2 = Math.Log(1/c);
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            a[0,0] = Math.Exp(l1);
+            for(i=1; i<=n-2; i++)
+            {
+                a[i,i] = Math.Exp(AP.Math.RandomReal()*(l2-l1)+l1);
+            }
+            a[n-1,n-1] = Math.Exp(l2);
+            rmatrixrndorthogonalfromtheleft(ref a, n, n);
+            rmatrixrndorthogonalfromtheright(ref a, n, n);
+        }
+
+
+        /*************************************************************************
+        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]
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void cmatrixrndorthogonal(int n,
+            ref AP.Complex[,] a)
+        {
+            int i = 0;
+            int j = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "CMatrixRndOrthogonal: N<1!");
+            a = new AP.Complex[n-1+1, n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        a[i,j] = 1;
+                    }
+                    else
+                    {
+                        a[i,j] = 0;
+                    }
+                }
+            }
+            cmatrixrndorthogonalfromtheright(ref a, n, n);
+        }
+
+
+        /*************************************************************************
+        Generation of random NxN complex matrix with given condition number C and
+        norm2(A)=1
+
+        INPUT PARAMETERS:
+            N   -   matrix size
+            C   -   condition number (in 2-norm)
+
+        OUTPUT PARAMETERS:
+            A   -   random matrix with norm2(A)=1 and cond(A)=C
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void cmatrixrndcond(int n,
+            double c,
+            ref AP.Complex[,] a)
+        {
+            int i = 0;
+            int j = 0;
+            double l1 = 0;
+            double l2 = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            AP.Complex v = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & (double)(c)>=(double)(1), "CMatrixRndCond: N<1 or C<1!");
+            a = new AP.Complex[n-1+1, n-1+1];
+            if( n==1 )
+            {
+                
+                //
+                // special case
+                //
+                hqrnd.hqrndrandomize(ref state);
+                hqrnd.hqrndunit2(ref state, ref v.x, ref v.y);
+                a[0,0] = v;
+                return;
+            }
+            l1 = 0;
+            l2 = Math.Log(1/c);
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            a[0,0] = Math.Exp(l1);
+            for(i=1; i<=n-2; i++)
+            {
+                a[i,i] = Math.Exp(AP.Math.RandomReal()*(l2-l1)+l1);
+            }
+            a[n-1,n-1] = Math.Exp(l2);
+            cmatrixrndorthogonalfromtheleft(ref a, n, n);
+            cmatrixrndorthogonalfromtheright(ref a, n, n);
+        }
+
+
+        /*************************************************************************
+        Generation of random NxN symmetric matrix with given condition number  and
+        norm2(A)=1
+
+        INPUT PARAMETERS:
+            N   -   matrix size
+            C   -   condition number (in 2-norm)
+
+        OUTPUT PARAMETERS:
+            A   -   random matrix with norm2(A)=1 and cond(A)=C
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void smatrixrndcond(int n,
+            double c,
+            ref double[,] a)
+        {
+            int i = 0;
+            int j = 0;
+            double l1 = 0;
+            double l2 = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & (double)(c)>=(double)(1), "SMatrixRndCond: N<1 or C<1!");
+            a = new double[n-1+1, n-1+1];
+            if( n==1 )
+            {
+                
+                //
+                // special case
+                //
+                a[0,0] = 2*AP.Math.RandomInteger(2)-1;
+                return;
+            }
+            
+            //
+            // Prepare matrix
+            //
+            l1 = 0;
+            l2 = Math.Log(1/c);
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            a[0,0] = Math.Exp(l1);
+            for(i=1; i<=n-2; i++)
+            {
+                a[i,i] = (2*AP.Math.RandomInteger(2)-1)*Math.Exp(AP.Math.RandomReal()*(l2-l1)+l1);
+            }
+            a[n-1,n-1] = Math.Exp(l2);
+            
+            //
+            // Multiply
+            //
+            smatrixrndmultiply(ref a, n);
+        }
+
+
+        /*************************************************************************
+        Generation of random NxN symmetric positive definite matrix with given
+        condition number and norm2(A)=1
+
+        INPUT PARAMETERS:
+            N   -   matrix size
+            C   -   condition number (in 2-norm)
+
+        OUTPUT PARAMETERS:
+            A   -   random SPD matrix with norm2(A)=1 and cond(A)=C
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void spdmatrixrndcond(int n,
+            double c,
+            ref double[,] a)
+        {
+            int i = 0;
+            int j = 0;
+            double l1 = 0;
+            double l2 = 0;
+
+            
+            //
+            // Special cases
+            //
+            if( n<=0 | (double)(c)<(double)(1) )
+            {
+                return;
+            }
+            a = new double[n-1+1, n-1+1];
+            if( n==1 )
+            {
+                a[0,0] = 1;
+                return;
+            }
+            
+            //
+            // Prepare matrix
+            //
+            l1 = 0;
+            l2 = Math.Log(1/c);
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            a[0,0] = Math.Exp(l1);
+            for(i=1; i<=n-2; i++)
+            {
+                a[i,i] = Math.Exp(AP.Math.RandomReal()*(l2-l1)+l1);
+            }
+            a[n-1,n-1] = Math.Exp(l2);
+            
+            //
+            // Multiply
+            //
+            smatrixrndmultiply(ref a, n);
+        }
+
+
+        /*************************************************************************
+        Generation of random NxN Hermitian matrix with given condition number  and
+        norm2(A)=1
+
+        INPUT PARAMETERS:
+            N   -   matrix size
+            C   -   condition number (in 2-norm)
+
+        OUTPUT PARAMETERS:
+            A   -   random matrix with norm2(A)=1 and cond(A)=C
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void hmatrixrndcond(int n,
+            double c,
+            ref AP.Complex[,] a)
+        {
+            int i = 0;
+            int j = 0;
+            double l1 = 0;
+            double l2 = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & (double)(c)>=(double)(1), "HMatrixRndCond: N<1 or C<1!");
+            a = new AP.Complex[n-1+1, n-1+1];
+            if( n==1 )
+            {
+                
+                //
+                // special case
+                //
+                a[0,0] = 2*AP.Math.RandomInteger(2)-1;
+                return;
+            }
+            
+            //
+            // Prepare matrix
+            //
+            l1 = 0;
+            l2 = Math.Log(1/c);
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            a[0,0] = Math.Exp(l1);
+            for(i=1; i<=n-2; i++)
+            {
+                a[i,i] = (2*AP.Math.RandomInteger(2)-1)*Math.Exp(AP.Math.RandomReal()*(l2-l1)+l1);
+            }
+            a[n-1,n-1] = Math.Exp(l2);
+            
+            //
+            // Multiply
+            //
+            hmatrixrndmultiply(ref a, n);
+        }
+
+
+        /*************************************************************************
+        Generation of random NxN Hermitian positive definite matrix with given
+        condition number and norm2(A)=1
+
+        INPUT PARAMETERS:
+            N   -   matrix size
+            C   -   condition number (in 2-norm)
+
+        OUTPUT PARAMETERS:
+            A   -   random HPD matrix with norm2(A)=1 and cond(A)=C
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void hpdmatrixrndcond(int n,
+            double c,
+            ref AP.Complex[,] a)
+        {
+            int i = 0;
+            int j = 0;
+            double l1 = 0;
+            double l2 = 0;
+
+            
+            //
+            // Special cases
+            //
+            if( n<=0 | (double)(c)<(double)(1) )
+            {
+                return;
+            }
+            a = new AP.Complex[n-1+1, n-1+1];
+            if( n==1 )
+            {
+                a[0,0] = 1;
+                return;
+            }
+            
+            //
+            // Prepare matrix
+            //
+            l1 = 0;
+            l2 = Math.Log(1/c);
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            a[0,0] = Math.Exp(l1);
+            for(i=1; i<=n-2; i++)
+            {
+                a[i,i] = Math.Exp(AP.Math.RandomReal()*(l2-l1)+l1);
+            }
+            a[n-1,n-1] = Math.Exp(l2);
+            
+            //
+            // Multiply
+            //
+            hmatrixrndmultiply(ref a, n);
+        }
+
+
+        /*************************************************************************
+        Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix
+
+        INPUT PARAMETERS:
+            A   -   matrix, array[0..M-1, 0..N-1]
+            M, N-   matrix size
+
+        OUTPUT PARAMETERS:
+            A   -   A*Q, where Q is random NxN orthogonal matrix
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixrndorthogonalfromtheright(ref double[,] a,
+            int m,
+            int n)
+        {
+            double tau = 0;
+            double lambda = 0;
+            int s = 0;
+            int i = 0;
+            int j = 0;
+            double u1 = 0;
+            double u2 = 0;
+            double[] w = new double[0];
+            double[] v = new double[0];
+            double sm = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!");
+            if( n==1 )
+            {
+                
+                //
+                // Special case
+                //
+                tau = 2*AP.Math.RandomInteger(2)-1;
+                for(i=0; i<=m-1; i++)
+                {
+                    a[i,0] = a[i,0]*tau;
+                }
+                return;
+            }
+            
+            //
+            // General case.
+            // First pass.
+            //
+            w = new double[m-1+1];
+            v = new double[n+1];
+            hqrnd.hqrndrandomize(ref state);
+            for(s=2; s<=n; s++)
+            {
+                
+                //
+                // Prepare random normal v
+                //
+                do
+                {
+                    i = 1;
+                    while( i<=s )
+                    {
+                        hqrnd.hqrndnormal2(ref state, ref u1, ref u2);
+                        v[i] = u1;
+                        if( i+1<=s )
+                        {
+                            v[i+1] = u2;
+                        }
+                        i = i+2;
+                    }
+                    lambda = 0.0;
+                    for(i_=1; i_<=s;i_++)
+                    {
+                        lambda += v[i_]*v[i_];
+                    }
+                }
+                while( (double)(lambda)==(double)(0) );
+                
+                //
+                // Prepare and apply reflection
+                //
+                reflections.generatereflection(ref v, s, ref tau);
+                v[1] = 1;
+                reflections.applyreflectionfromtheright(ref a, tau, ref v, 0, m-1, n-s, n-1, ref w);
+            }
+            
+            //
+            // Second pass.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                tau = 2*AP.Math.RandomInteger(2)-1;
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    a[i_,i] = tau*a[i_,i];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix
+
+        INPUT PARAMETERS:
+            A   -   matrix, array[0..M-1, 0..N-1]
+            M, N-   matrix size
+
+        OUTPUT PARAMETERS:
+            A   -   Q*A, where Q is random MxM orthogonal matrix
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixrndorthogonalfromtheleft(ref double[,] a,
+            int m,
+            int n)
+        {
+            double tau = 0;
+            double lambda = 0;
+            int s = 0;
+            int i = 0;
+            int j = 0;
+            double u1 = 0;
+            double u2 = 0;
+            double[] w = new double[0];
+            double[] v = new double[0];
+            double sm = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!");
+            if( m==1 )
+            {
+                
+                //
+                // special case
+                //
+                tau = 2*AP.Math.RandomInteger(2)-1;
+                for(j=0; j<=n-1; j++)
+                {
+                    a[0,j] = a[0,j]*tau;
+                }
+                return;
+            }
+            
+            //
+            // General case.
+            // First pass.
+            //
+            w = new double[n-1+1];
+            v = new double[m+1];
+            hqrnd.hqrndrandomize(ref state);
+            for(s=2; s<=m; s++)
+            {
+                
+                //
+                // Prepare random normal v
+                //
+                do
+                {
+                    i = 1;
+                    while( i<=s )
+                    {
+                        hqrnd.hqrndnormal2(ref state, ref u1, ref u2);
+                        v[i] = u1;
+                        if( i+1<=s )
+                        {
+                            v[i+1] = u2;
+                        }
+                        i = i+2;
+                    }
+                    lambda = 0.0;
+                    for(i_=1; i_<=s;i_++)
+                    {
+                        lambda += v[i_]*v[i_];
+                    }
+                }
+                while( (double)(lambda)==(double)(0) );
+                
+                //
+                // Prepare and apply reflection
+                //
+                reflections.generatereflection(ref v, s, ref tau);
+                v[1] = 1;
+                reflections.applyreflectionfromtheleft(ref a, tau, ref v, m-s, m-1, 0, n-1, ref w);
+            }
+            
+            //
+            // Second pass.
+            //
+            for(i=0; i<=m-1; i++)
+            {
+                tau = 2*AP.Math.RandomInteger(2)-1;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    a[i,i_] = tau*a[i,i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Multiplication of MxN complex matrix by NxN random Haar distributed
+        complex orthogonal matrix
+
+        INPUT PARAMETERS:
+            A   -   matrix, array[0..M-1, 0..N-1]
+            M, N-   matrix size
+
+        OUTPUT PARAMETERS:
+            A   -   A*Q, where Q is random NxN orthogonal matrix
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void cmatrixrndorthogonalfromtheright(ref AP.Complex[,] a,
+            int m,
+            int n)
+        {
+            AP.Complex lambda = 0;
+            AP.Complex tau = 0;
+            int s = 0;
+            int i = 0;
+            int j = 0;
+            double u1 = 0;
+            double u2 = 0;
+            AP.Complex[] w = new AP.Complex[0];
+            AP.Complex[] v = new AP.Complex[0];
+            double sm = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!");
+            if( n==1 )
+            {
+                
+                //
+                // Special case
+                //
+                hqrnd.hqrndrandomize(ref state);
+                hqrnd.hqrndunit2(ref state, ref tau.x, ref tau.y);
+                for(i=0; i<=m-1; i++)
+                {
+                    a[i,0] = a[i,0]*tau;
+                }
+                return;
+            }
+            
+            //
+            // General case.
+            // First pass.
+            //
+            w = new AP.Complex[m-1+1];
+            v = new AP.Complex[n+1];
+            hqrnd.hqrndrandomize(ref state);
+            for(s=2; s<=n; s++)
+            {
+                
+                //
+                // Prepare random normal v
+                //
+                do
+                {
+                    for(i=1; i<=s; i++)
+                    {
+                        hqrnd.hqrndnormal2(ref state, ref tau.x, ref tau.y);
+                        v[i] = tau;
+                    }
+                    lambda = 0.0;
+                    for(i_=1; i_<=s;i_++)
+                    {
+                        lambda += v[i_]*AP.Math.Conj(v[i_]);
+                    }
+                }
+                while( lambda==0 );
+                
+                //
+                // Prepare and apply reflection
+                //
+                creflections.complexgeneratereflection(ref v, s, ref tau);
+                v[1] = 1;
+                creflections.complexapplyreflectionfromtheright(ref a, tau, ref v, 0, m-1, n-s, n-1, ref w);
+            }
+            
+            //
+            // Second pass.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                hqrnd.hqrndunit2(ref state, ref tau.x, ref tau.y);
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    a[i_,i] = tau*a[i_,i];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Multiplication of MxN complex matrix by MxM random Haar distributed
+        complex orthogonal matrix
+
+        INPUT PARAMETERS:
+            A   -   matrix, array[0..M-1, 0..N-1]
+            M, N-   matrix size
+
+        OUTPUT PARAMETERS:
+            A   -   Q*A, where Q is random MxM orthogonal matrix
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void cmatrixrndorthogonalfromtheleft(ref AP.Complex[,] a,
+            int m,
+            int n)
+        {
+            AP.Complex tau = 0;
+            AP.Complex lambda = 0;
+            int s = 0;
+            int i = 0;
+            int j = 0;
+            double u1 = 0;
+            double u2 = 0;
+            AP.Complex[] w = new AP.Complex[0];
+            AP.Complex[] v = new AP.Complex[0];
+            double sm = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1 & m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!");
+            if( m==1 )
+            {
+                
+                //
+                // special case
+                //
+                hqrnd.hqrndrandomize(ref state);
+                hqrnd.hqrndunit2(ref state, ref tau.x, ref tau.y);
+                for(j=0; j<=n-1; j++)
+                {
+                    a[0,j] = a[0,j]*tau;
+                }
+                return;
+            }
+            
+            //
+            // General case.
+            // First pass.
+            //
+            w = new AP.Complex[n-1+1];
+            v = new AP.Complex[m+1];
+            hqrnd.hqrndrandomize(ref state);
+            for(s=2; s<=m; s++)
+            {
+                
+                //
+                // Prepare random normal v
+                //
+                do
+                {
+                    for(i=1; i<=s; i++)
+                    {
+                        hqrnd.hqrndnormal2(ref state, ref tau.x, ref tau.y);
+                        v[i] = tau;
+                    }
+                    lambda = 0.0;
+                    for(i_=1; i_<=s;i_++)
+                    {
+                        lambda += v[i_]*AP.Math.Conj(v[i_]);
+                    }
+                }
+                while( lambda==0 );
+                
+                //
+                // Prepare and apply reflection
+                //
+                creflections.complexgeneratereflection(ref v, s, ref tau);
+                v[1] = 1;
+                creflections.complexapplyreflectionfromtheleft(ref a, tau, ref v, m-s, m-1, 0, n-1, ref w);
+            }
+            
+            //
+            // Second pass.
+            //
+            for(i=0; i<=m-1; i++)
+            {
+                hqrnd.hqrndunit2(ref state, ref tau.x, ref tau.y);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    a[i,i_] = tau*a[i,i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Symmetric multiplication of NxN matrix by random Haar distributed
+        orthogonal  matrix
+
+        INPUT PARAMETERS:
+            A   -   matrix, array[0..N-1, 0..N-1]
+            N   -   matrix size
+
+        OUTPUT PARAMETERS:
+            A   -   Q'*A*Q, where Q is random NxN orthogonal matrix
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void smatrixrndmultiply(ref double[,] a,
+            int n)
+        {
+            double tau = 0;
+            double lambda = 0;
+            int s = 0;
+            int i = 0;
+            int j = 0;
+            double u1 = 0;
+            double u2 = 0;
+            double[] w = new double[0];
+            double[] v = new double[0];
+            double sm = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            int i_ = 0;
+
+            
+            //
+            // General case.
+            //
+            w = new double[n-1+1];
+            v = new double[n+1];
+            hqrnd.hqrndrandomize(ref state);
+            for(s=2; s<=n; s++)
+            {
+                
+                //
+                // Prepare random normal v
+                //
+                do
+                {
+                    i = 1;
+                    while( i<=s )
+                    {
+                        hqrnd.hqrndnormal2(ref state, ref u1, ref u2);
+                        v[i] = u1;
+                        if( i+1<=s )
+                        {
+                            v[i+1] = u2;
+                        }
+                        i = i+2;
+                    }
+                    lambda = 0.0;
+                    for(i_=1; i_<=s;i_++)
+                    {
+                        lambda += v[i_]*v[i_];
+                    }
+                }
+                while( (double)(lambda)==(double)(0) );
+                
+                //
+                // Prepare and apply reflection
+                //
+                reflections.generatereflection(ref v, s, ref tau);
+                v[1] = 1;
+                reflections.applyreflectionfromtheright(ref a, tau, ref v, 0, n-1, n-s, n-1, ref w);
+                reflections.applyreflectionfromtheleft(ref a, tau, ref v, n-s, n-1, 0, n-1, ref w);
+            }
+            
+            //
+            // Second pass.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                tau = 2*AP.Math.RandomInteger(2)-1;
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    a[i_,i] = tau*a[i_,i];
+                }
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    a[i,i_] = tau*a[i,i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Hermitian multiplication of NxN matrix by random Haar distributed
+        complex orthogonal matrix
+
+        INPUT PARAMETERS:
+            A   -   matrix, array[0..N-1, 0..N-1]
+            N   -   matrix size
+
+        OUTPUT PARAMETERS:
+            A   -   Q^H*A*Q, where Q is random NxN orthogonal matrix
+
+          -- ALGLIB routine --
+             04.12.2009
+             Bochkanov Sergey
+        *************************************************************************/
+        public static void hmatrixrndmultiply(ref AP.Complex[,] a,
+            int n)
+        {
+            AP.Complex tau = 0;
+            AP.Complex lambda = 0;
+            int s = 0;
+            int i = 0;
+            int j = 0;
+            double u1 = 0;
+            double u2 = 0;
+            AP.Complex[] w = new AP.Complex[0];
+            AP.Complex[] v = new AP.Complex[0];
+            double sm = 0;
+            hqrnd.hqrndstate state = new hqrnd.hqrndstate();
+            int i_ = 0;
+
+            
+            //
+            // General case.
+            //
+            w = new AP.Complex[n-1+1];
+            v = new AP.Complex[n+1];
+            hqrnd.hqrndrandomize(ref state);
+            for(s=2; s<=n; s++)
+            {
+                
+                //
+                // Prepare random normal v
+                //
+                do
+                {
+                    for(i=1; i<=s; i++)
+                    {
+                        hqrnd.hqrndnormal2(ref state, ref tau.x, ref tau.y);
+                        v[i] = tau;
+                    }
+                    lambda = 0.0;
+                    for(i_=1; i_<=s;i_++)
+                    {
+                        lambda += v[i_]*AP.Math.Conj(v[i_]);
+                    }
+                }
+                while( lambda==0 );
+                
+                //
+                // Prepare and apply reflection
+                //
+                creflections.complexgeneratereflection(ref v, s, ref tau);
+                v[1] = 1;
+                creflections.complexapplyreflectionfromtheright(ref a, tau, ref v, 0, n-1, n-s, n-1, ref w);
+                creflections.complexapplyreflectionfromtheleft(ref a, AP.Math.Conj(tau), ref v, n-s, n-1, 0, n-1, ref w);
+            }
+            
+            //
+            // Second pass.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                hqrnd.hqrndunit2(ref state, ref tau.x, ref tau.y);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    a[i_,i] = tau*a[i_,i];
+                }
+                tau = AP.Math.Conj(tau);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    a[i,i_] = tau*a[i,i_];
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/minlm.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/minlm.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/minlm.cs	(revision 2645)
@@ -0,0 +1,1044 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class minlm
+    {
+        public struct lmstate
+        {
+            public bool wrongparams;
+            public int n;
+            public int m;
+            public double epsf;
+            public double epsx;
+            public int maxits;
+            public int flags;
+            public int usermode;
+            public double[] x;
+            public double f;
+            public double[] fi;
+            public double[,] j;
+            public double[,] h;
+            public double[] g;
+            public bool needf;
+            public bool needfg;
+            public bool needfgh;
+            public bool needfij;
+            public bool xupdated;
+            public lbfgs.lbfgsstate internalstate;
+            public lbfgs.lbfgsreport internalrep;
+            public double[] xprec;
+            public double[] xbase;
+            public double[] xdir;
+            public double[] gbase;
+            public double[,] rawmodel;
+            public double[,] model;
+            public double[] work;
+            public AP.rcommstate rstate;
+            public int repiterationscount;
+            public int repterminationtype;
+            public int repnfunc;
+            public int repnjac;
+            public int repngrad;
+            public int repnhess;
+            public int repncholesky;
+        };
+
+
+        public struct lmreport
+        {
+            public int iterationscount;
+            public int terminationtype;
+            public int nfunc;
+            public int njac;
+            public int ngrad;
+            public int nhess;
+            public int ncholesky;
+        };
+
+
+
+
+        public const int lmmodefj = 0;
+        public const int lmmodefgj = 1;
+        public const int lmmodefgh = 2;
+        public const int lmflagnoprelbfgs = 1;
+        public const int lmflagnointlbfgs = 2;
+        public const int lmprelbfgsm = 5;
+        public const int lmintlbfgsits = 5;
+        public const int lbfgsnorealloc = 1;
+
+
+        /*************************************************************************
+            LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION
+
+        Optimization using function gradient and Hessian.  Algorithm -  Levenberg-
+        Marquardt   modification   with   L-BFGS   pre-optimization  and  internal
+        pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step.
+
+        Function F has general form (not "sum-of-squares"):
+
+            F = F(x[0], ..., x[n-1])
+
+        EXAMPLE
+
+        See HTML-documentation.
+
+        INPUT PARAMETERS:
+            N       -   dimension, N>1
+            X       -   initial solution, array[0..N-1]
+            EpsF    -   stopping criterion. Algorithm stops if
+                        |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
+            EpsX    -   stopping criterion. Algorithm stops if
+                        |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
+            MaxIts  -   stopping criterion. Algorithm stops after MaxIts iterations.
+                        MaxIts=0 means no stopping criterion.
+
+        OUTPUT PARAMETERS:
+            State   -   structure which stores algorithm state between subsequent
+                        calls of MinLMIteration. Used for reverse communication.
+                        This structure should be passed to MinLMIteration subroutine.
+
+        See also MinLMIteration, MinLMResults.
+
+        NOTE
+
+        Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
+        stopping criterion selection (small EpsX).
+
+          -- ALGLIB --
+             Copyright 30.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void minlmfgh(int n,
+            ref double[] x,
+            double epsf,
+            double epsx,
+            int maxits,
+            ref lmstate state)
+        {
+            int i_ = 0;
+
+            
+            //
+            // Prepare RComm
+            //
+            state.rstate.ia = new int[3+1];
+            state.rstate.ba = new bool[0+1];
+            state.rstate.ra = new double[8+1];
+            state.rstate.stage = -1;
+            
+            //
+            // prepare internal structures
+            //
+            lmprepare(n, 0, true, ref state);
+            
+            //
+            // initialize, check parameters
+            //
+            state.xupdated = false;
+            state.n = n;
+            state.m = 0;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.flags = 0;
+            if( (double)(state.epsf)==(double)(0) & (double)(state.epsx)==(double)(0) & state.maxits==0 )
+            {
+                state.epsx = 1.0E-6;
+            }
+            state.usermode = lmmodefgh;
+            state.wrongparams = false;
+            if( n<1 | (double)(epsf)<(double)(0) | (double)(epsx)<(double)(0) | maxits<0 )
+            {
+                state.wrongparams = true;
+                return;
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.x[i_] = x[i_];
+            }
+        }
+
+
+        /*************************************************************************
+            LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION
+
+        Optimization using function gradient and Jacobian.  Algorithm -  Levenberg-
+        Marquardt   modification   with   L-BFGS   pre-optimization  and  internal
+        pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step.
+
+        Function F is represented as sum of squares:
+
+            F = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])
+
+        EXAMPLE
+
+        See HTML-documentation.
+
+        INPUT PARAMETERS:
+            N       -   dimension, N>1
+            M       -   number of functions f[i]
+            X       -   initial solution, array[0..N-1]
+            EpsF    -   stopping criterion. Algorithm stops if
+                        |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
+            EpsX    -   stopping criterion. Algorithm stops if
+                        |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
+            MaxIts  -   stopping criterion. Algorithm stops after MaxIts iterations.
+                        MaxIts=0 means no stopping criterion.
+
+        OUTPUT PARAMETERS:
+            State   -   structure which stores algorithm state between subsequent
+                        calls of MinLMIteration. Used for reverse communication.
+                        This structure should be passed to MinLMIteration subroutine.
+
+        See also MinLMIteration, MinLMResults.
+
+        NOTE
+
+        Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
+        stopping criterion selection (small EpsX).
+
+          -- ALGLIB --
+             Copyright 30.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void minlmfgj(int n,
+            int m,
+            ref double[] x,
+            double epsf,
+            double epsx,
+            int maxits,
+            ref lmstate state)
+        {
+            int i_ = 0;
+
+            
+            //
+            // Prepare RComm
+            //
+            state.rstate.ia = new int[3+1];
+            state.rstate.ba = new bool[0+1];
+            state.rstate.ra = new double[8+1];
+            state.rstate.stage = -1;
+            
+            //
+            // prepare internal structures
+            //
+            lmprepare(n, m, true, ref state);
+            
+            //
+            // initialize, check parameters
+            //
+            state.xupdated = false;
+            state.n = n;
+            state.m = m;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.flags = 0;
+            if( (double)(state.epsf)==(double)(0) & (double)(state.epsx)==(double)(0) & state.maxits==0 )
+            {
+                state.epsx = 1.0E-6;
+            }
+            state.usermode = lmmodefgj;
+            state.wrongparams = false;
+            if( n<1 | m<1 | (double)(epsf)<(double)(0) | (double)(epsx)<(double)(0) | maxits<0 )
+            {
+                state.wrongparams = true;
+                return;
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.x[i_] = x[i_];
+            }
+        }
+
+
+        /*************************************************************************
+            CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR OPTIMIZATION
+
+        Optimization using Jacobi matrix. Algorithm  -  classic Levenberg-Marquardt
+        method.
+
+        Function F is represented as sum of squares:
+
+            F = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])
+
+        EXAMPLE
+
+        See HTML-documentation.
+
+        INPUT PARAMETERS:
+            N       -   dimension, N>1
+            M       -   number of functions f[i]
+            X       -   initial solution, array[0..N-1]
+            EpsF    -   stopping criterion. Algorithm stops if
+                        |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
+            EpsX    -   stopping criterion. Algorithm stops if
+                        |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
+            MaxIts  -   stopping criterion. Algorithm stops after MaxIts iterations.
+                        MaxIts=0 means no stopping criterion.
+
+        OUTPUT PARAMETERS:
+            State   -   structure which stores algorithm state between subsequent
+                        calls of MinLMIteration. Used for reverse communication.
+                        This structure should be passed to MinLMIteration subroutine.
+
+        See also MinLMIteration, MinLMResults.
+
+        NOTE
+
+        Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
+        stopping criterion selection (small EpsX).
+
+          -- ALGLIB --
+             Copyright 30.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void minlmfj(int n,
+            int m,
+            ref double[] x,
+            double epsf,
+            double epsx,
+            int maxits,
+            ref lmstate state)
+        {
+            int i_ = 0;
+
+            
+            //
+            // Prepare RComm
+            //
+            state.rstate.ia = new int[3+1];
+            state.rstate.ba = new bool[0+1];
+            state.rstate.ra = new double[8+1];
+            state.rstate.stage = -1;
+            
+            //
+            // prepare internal structures
+            //
+            lmprepare(n, m, true, ref state);
+            
+            //
+            // initialize, check parameters
+            //
+            state.xupdated = false;
+            state.n = n;
+            state.m = m;
+            state.epsf = epsf;
+            state.epsx = epsx;
+            state.maxits = maxits;
+            state.flags = 0;
+            if( (double)(state.epsf)==(double)(0) & (double)(state.epsx)==(double)(0) & state.maxits==0 )
+            {
+                state.epsx = 1.0E-6;
+            }
+            state.usermode = lmmodefj;
+            state.wrongparams = false;
+            if( n<1 | m<1 | (double)(epsf)<(double)(0) | (double)(epsx)<(double)(0) | maxits<0 )
+            {
+                state.wrongparams = true;
+                return;
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.x[i_] = x[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        One Levenberg-Marquardt iteration.
+
+        Called after inialization of State structure with MinLMXXX subroutine.
+        See HTML docs for examples.
+
+        Input parameters:
+            State   -   structure which stores algorithm state between subsequent
+                        calls and which is used for reverse communication. Must be
+                        initialized with MinLMXXX call first.
+
+        If subroutine returned False, iterative algorithm has converged.
+
+        If subroutine returned True, then:
+        * if State.NeedF=True,      -   function value F at State.X[0..N-1]
+                                        is required
+        * if State.NeedFG=True      -   function value F and gradient G
+                                        are required
+        * if State.NeedFiJ=True     -   function vector f[i] and Jacobi matrix J
+                                        are required
+        * if State.NeedFGH=True     -   function value F, gradient G and Hesian H
+                                        are required
+
+        One and only one of this fields can be set at time.
+
+        Results are stored:
+        * function value            -   in LMState.F
+        * gradient                  -   in LMState.G[0..N-1]
+        * Jacobi matrix             -   in LMState.J[0..M-1,0..N-1]
+        * Hessian                   -   in LMState.H[0..N-1,0..N-1]
+
+          -- ALGLIB --
+             Copyright 10.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool minlmiteration(ref lmstate state)
+        {
+            bool result = new bool();
+            int n = 0;
+            int m = 0;
+            int i = 0;
+            double xnorm = 0;
+            double stepnorm = 0;
+            bool spd = new bool();
+            double fbase = 0;
+            double fnew = 0;
+            double lambda = 0;
+            double nu = 0;
+            double lambdaup = 0;
+            double lambdadown = 0;
+            int lbfgsflags = 0;
+            double v = 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.rstate.stage>=0 )
+            {
+                n = state.rstate.ia[0];
+                m = state.rstate.ia[1];
+                i = state.rstate.ia[2];
+                lbfgsflags = state.rstate.ia[3];
+                spd = state.rstate.ba[0];
+                xnorm = state.rstate.ra[0];
+                stepnorm = state.rstate.ra[1];
+                fbase = state.rstate.ra[2];
+                fnew = state.rstate.ra[3];
+                lambda = state.rstate.ra[4];
+                nu = state.rstate.ra[5];
+                lambdaup = state.rstate.ra[6];
+                lambdadown = state.rstate.ra[7];
+                v = state.rstate.ra[8];
+            }
+            else
+            {
+                n = -983;
+                m = -989;
+                i = -834;
+                lbfgsflags = 900;
+                spd = true;
+                xnorm = 364;
+                stepnorm = 214;
+                fbase = -338;
+                fnew = -686;
+                lambda = 912;
+                nu = 585;
+                lambdaup = 497;
+                lambdadown = -271;
+                v = -581;
+            }
+            if( state.rstate.stage==0 )
+            {
+                goto lbl_0;
+            }
+            if( state.rstate.stage==1 )
+            {
+                goto lbl_1;
+            }
+            if( state.rstate.stage==2 )
+            {
+                goto lbl_2;
+            }
+            if( state.rstate.stage==3 )
+            {
+                goto lbl_3;
+            }
+            if( state.rstate.stage==4 )
+            {
+                goto lbl_4;
+            }
+            if( state.rstate.stage==5 )
+            {
+                goto lbl_5;
+            }
+            if( state.rstate.stage==6 )
+            {
+                goto lbl_6;
+            }
+            
+            //
+            // Routine body
+            //
+            System.Diagnostics.Debug.Assert(state.usermode==lmmodefj | state.usermode==lmmodefgj | state.usermode==lmmodefgh, "LM: internal error");
+            if( state.wrongparams )
+            {
+                state.repterminationtype = -1;
+                result = false;
+                return result;
+            }
+            
+            //
+            // prepare params
+            //
+            n = state.n;
+            m = state.m;
+            lambdaup = 10;
+            lambdadown = 0.3;
+            nu = 2;
+            lbfgsflags = 0;
+            
+            //
+            // if we have F and G
+            //
+            if( ! ((state.usermode==lmmodefgj | state.usermode==lmmodefgh) & state.flags/lmflagnoprelbfgs%2==0) )
+            {
+                goto lbl_7;
+            }
+            
+            //
+            // First stage of the hybrid algorithm: LBFGS
+            //
+            lbfgs.minlbfgs(n, Math.Min(n, lmprelbfgsm), ref state.x, 0.0, 0.0, 0.0, Math.Max(25, n), 0, ref state.internalstate);
+        lbl_9:
+            if( ! lbfgs.minlbfgsiteration(ref state.internalstate) )
+            {
+                goto lbl_10;
+            }
+            
+            //
+            // RComm
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.x[i_] = state.internalstate.x[i_];
+            }
+            lmclearrequestfields(ref state);
+            state.needfg = true;
+            state.rstate.stage = 0;
+            goto lbl_rcomm;
+        lbl_0:
+            state.repnfunc = state.repnfunc+1;
+            state.repngrad = state.repngrad+1;
+            
+            //
+            // Call LBFGS
+            //
+            state.internalstate.f = state.f;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.internalstate.g[i_] = state.g[i_];
+            }
+            goto lbl_9;
+        lbl_10:
+            lbfgs.minlbfgsresults(ref state.internalstate, ref state.x, ref state.internalrep);
+        lbl_7:
+            
+            //
+            // Second stage of the hybrid algorithm: LM
+            // Initialize quadratic model.
+            //
+            if( state.usermode!=lmmodefgh )
+            {
+                goto lbl_11;
+            }
+            
+            //
+            // RComm
+            //
+            lmclearrequestfields(ref state);
+            state.needfgh = true;
+            state.rstate.stage = 1;
+            goto lbl_rcomm;
+        lbl_1:
+            state.repnfunc = state.repnfunc+1;
+            state.repngrad = state.repngrad+1;
+            state.repnhess = state.repnhess+1;
+            
+            //
+            // generate raw quadratic model
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.rawmodel[i,i_] = state.h[i,i_];
+                }
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.gbase[i_] = state.g[i_];
+            }
+            fbase = state.f;
+        lbl_11:
+            if( ! (state.usermode==lmmodefgj | state.usermode==lmmodefj) )
+            {
+                goto lbl_13;
+            }
+            
+            //
+            // RComm
+            //
+            lmclearrequestfields(ref state);
+            state.needfij = true;
+            state.rstate.stage = 2;
+            goto lbl_rcomm;
+        lbl_2:
+            state.repnfunc = state.repnfunc+1;
+            state.repnjac = state.repnjac+1;
+            
+            //
+            // generate raw quadratic model
+            //
+            blas.matrixmatrixmultiply(ref state.j, 0, m-1, 0, n-1, true, ref state.j, 0, m-1, 0, n-1, false, 1.0, ref state.rawmodel, 0, n-1, 0, n-1, 0.0, ref state.work);
+            blas.matrixvectormultiply(ref state.j, 0, m-1, 0, n-1, true, ref state.fi, 0, m-1, 1.0, ref state.gbase, 0, n-1, 0.0);
+            fbase = 0.0;
+            for(i_=0; i_<=m-1;i_++)
+            {
+                fbase += state.fi[i_]*state.fi[i_];
+            }
+        lbl_13:
+            lambda = 0.001;
+        lbl_15:
+            if( false )
+            {
+                goto lbl_16;
+            }
+            
+            //
+            // 1. Model = RawModel+lambda*I
+            // 2. Try to solve (RawModel+Lambda*I)*dx = -g.
+            //    Increase lambda if left part is not positive definite.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.model[i,i_] = state.rawmodel[i,i_];
+                }
+                state.model[i,i] = state.model[i,i]+lambda;
+            }
+            spd = cholesky.spdmatrixcholesky(ref state.model, n, true);
+            state.repncholesky = state.repncholesky+1;
+            if( !spd )
+            {
+                lambda = lambda*lambdaup*nu;
+                nu = nu*2;
+                goto lbl_15;
+            }
+            if( !spdsolve.spdmatrixcholeskysolve(ref state.model, state.gbase, n, true, ref state.xdir) )
+            {
+                lambda = lambda*lambdaup*nu;
+                nu = nu*2;
+                goto lbl_15;
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.xdir[i_] = -1*state.xdir[i_];
+            }
+            
+            //
+            // Candidate 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_<=n-1;i_++)
+            {
+                state.xbase[i_] = state.x[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.x[i_] = state.x[i_] + state.xdir[i_];
+            }
+            xnorm = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                xnorm += state.xbase[i_]*state.xbase[i_];
+            }
+            stepnorm = 0.0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                stepnorm += state.xdir[i_]*state.xdir[i_];
+            }
+            xnorm = Math.Sqrt(xnorm);
+            stepnorm = Math.Sqrt(stepnorm);
+            if( (double)(stepnorm)<=(double)(state.epsx*(1+xnorm)) )
+            {
+                
+                //
+                // step size if small enough
+                //
+                state.repterminationtype = 2;
+                goto lbl_16;
+            }
+            lmclearrequestfields(ref state);
+            state.needf = true;
+            state.rstate.stage = 3;
+            goto lbl_rcomm;
+        lbl_3:
+            state.repnfunc = state.repnfunc+1;
+            fnew = state.f;
+            if( (double)(Math.Abs(fnew-fbase))<=(double)(state.epsf*Math.Max(1, Math.Max(Math.Abs(fbase), Math.Abs(fnew)))) )
+            {
+                
+                //
+                // function change is small enough
+                //
+                state.repterminationtype = 1;
+                goto lbl_16;
+            }
+            if( (double)(fnew)>(double)(fbase) )
+            {
+                
+                //
+                // restore state and continue out search for lambda
+                //
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.x[i_] = state.xbase[i_];
+                }
+                lambda = lambda*lambdaup*nu;
+                nu = nu*2;
+                goto lbl_15;
+            }
+            if( ! ((state.usermode==lmmodefgj | state.usermode==lmmodefgh) & state.flags/lmflagnointlbfgs%2==0) )
+            {
+                goto lbl_17;
+            }
+            System.Diagnostics.Debug.Assert(state.usermode==lmmodefgh);
+            
+            //
+            // Optimize using inv(cholesky(H)) as preconditioner
+            //
+            if( ! trinverse.rmatrixtrinverse(ref state.model, n, true, false) )
+            {
+                goto lbl_19;
+            }
+            
+            //
+            // if matrix can be inverted use it.
+            // just silently move to next iteration otherwise.
+            // (will be very, very rare, mostly for specially
+            // designed near-degenerate tasks)
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.xbase[i_] = state.x[i_];
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                state.xprec[i] = 0;
+            }
+            lbfgs.minlbfgs(n, Math.Min(n, lmintlbfgsits), ref state.xprec, 0.0, 0.0, 0.0, lmintlbfgsits, lbfgsflags, ref state.internalstate);
+        lbl_21:
+            if( ! lbfgs.minlbfgsiteration(ref state.internalstate) )
+            {
+                goto lbl_22;
+            }
+            
+            //
+            // convert XPrec to unpreconditioned form, then call RComm.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                v = 0.0;
+                for(i_=i; i_<=n-1;i_++)
+                {
+                    v += state.internalstate.x[i_]*state.model[i,i_];
+                }
+                state.x[i] = state.xbase[i]+v;
+            }
+            lmclearrequestfields(ref state);
+            state.needfg = true;
+            state.rstate.stage = 4;
+            goto lbl_rcomm;
+        lbl_4:
+            state.repnfunc = state.repnfunc+1;
+            state.repngrad = state.repngrad+1;
+            
+            //
+            // 1. pass State.F to State.InternalState.F
+            // 2. convert gradient back to preconditioned form
+            //
+            state.internalstate.f = state.f;
+            for(i=0; i<=n-1; i++)
+            {
+                state.internalstate.g[i] = 0;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                v = state.g[i];
+                for(i_=i; i_<=n-1;i_++)
+                {
+                    state.internalstate.g[i_] = state.internalstate.g[i_] + v*state.model[i,i_];
+                }
+            }
+            
+            //
+            // next iteration
+            //
+            goto lbl_21;
+        lbl_22:
+            
+            //
+            // change LBFGS flags to NoRealloc.
+            // L-BFGS subroutine will use memory allocated from previous run.
+            // it is possible since all subsequent calls will be with same N/M.
+            //
+            lbfgsflags = lbfgsnorealloc;
+            
+            //
+            // back to unpreconditioned X
+            //
+            lbfgs.minlbfgsresults(ref state.internalstate, ref state.xprec, ref state.internalrep);
+            for(i=0; i<=n-1; i++)
+            {
+                v = 0.0;
+                for(i_=i; i_<=n-1;i_++)
+                {
+                    v += state.xprec[i_]*state.model[i,i_];
+                }
+                state.x[i] = state.xbase[i]+v;
+            }
+        lbl_19:
+        lbl_17:
+            
+            //
+            // Accept new position.
+            // Calculate Hessian
+            //
+            if( state.usermode!=lmmodefgh )
+            {
+                goto lbl_23;
+            }
+            
+            //
+            // RComm
+            //
+            lmclearrequestfields(ref state);
+            state.needfgh = true;
+            state.rstate.stage = 5;
+            goto lbl_rcomm;
+        lbl_5:
+            state.repnfunc = state.repnfunc+1;
+            state.repngrad = state.repngrad+1;
+            state.repnhess = state.repnhess+1;
+            
+            //
+            // Update raw quadratic model
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.rawmodel[i,i_] = state.h[i,i_];
+                }
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.gbase[i_] = state.g[i_];
+            }
+            fbase = state.f;
+        lbl_23:
+            if( ! (state.usermode==lmmodefgj | state.usermode==lmmodefj) )
+            {
+                goto lbl_25;
+            }
+            
+            //
+            // RComm
+            //
+            lmclearrequestfields(ref state);
+            state.needfij = true;
+            state.rstate.stage = 6;
+            goto lbl_rcomm;
+        lbl_6:
+            state.repnfunc = state.repnfunc+1;
+            state.repnjac = state.repnjac+1;
+            
+            //
+            // generate raw quadratic model
+            //
+            blas.matrixmatrixmultiply(ref state.j, 0, m-1, 0, n-1, true, ref state.j, 0, m-1, 0, n-1, false, 1.0, ref state.rawmodel, 0, n-1, 0, n-1, 0.0, ref state.work);
+            blas.matrixvectormultiply(ref state.j, 0, m-1, 0, n-1, true, ref state.fi, 0, m-1, 1.0, ref state.gbase, 0, n-1, 0.0);
+            fbase = 0.0;
+            for(i_=0; i_<=m-1;i_++)
+            {
+                fbase += state.fi[i_]*state.fi[i_];
+            }
+        lbl_25:
+            state.repiterationscount = state.repiterationscount+1;
+            if( state.repiterationscount>=state.maxits & state.maxits>0 )
+            {
+                state.repterminationtype = 5;
+                goto lbl_16;
+            }
+            
+            //
+            // Update lambda
+            //
+            lambda = lambda*lambdadown;
+            nu = 2;
+            goto lbl_15;
+        lbl_16:
+            result = false;
+            return result;
+            
+            //
+            // Saving state
+            //
+        lbl_rcomm:
+            result = true;
+            state.rstate.ia[0] = n;
+            state.rstate.ia[1] = m;
+            state.rstate.ia[2] = i;
+            state.rstate.ia[3] = lbfgsflags;
+            state.rstate.ba[0] = spd;
+            state.rstate.ra[0] = xnorm;
+            state.rstate.ra[1] = stepnorm;
+            state.rstate.ra[2] = fbase;
+            state.rstate.ra[3] = fnew;
+            state.rstate.ra[4] = lambda;
+            state.rstate.ra[5] = nu;
+            state.rstate.ra[6] = lambdaup;
+            state.rstate.ra[7] = lambdadown;
+            state.rstate.ra[8] = v;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Levenberg-Marquardt algorithm results
+
+        Called after MinLMIteration returned False.
+
+        Input parameters:
+            State   -   algorithm state (used by MinLMIteration).
+
+        Output parameters:
+            X       -   array[0..N-1], solution
+            Rep     -   optimization report:
+                        * Rep.TerminationType completetion code:
+                            * -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
+                        * Rep.IterationsCount contains iterations count
+                        * Rep.NFunc     - number of function calculations
+                        * Rep.NJac      - number of Jacobi matrix calculations
+                        * Rep.NGrad     - number of gradient calculations
+                        * Rep.NHess     - number of Hessian calculations
+                        * Rep.NCholesky - number of Cholesky decomposition calculations
+
+          -- ALGLIB --
+             Copyright 10.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void minlmresults(ref lmstate state,
+            ref double[] x,
+            ref lmreport rep)
+        {
+            int i_ = 0;
+
+            x = new double[state.n-1+1];
+            for(i_=0; i_<=state.n-1;i_++)
+            {
+                x[i_] = state.x[i_];
+            }
+            rep.iterationscount = state.repiterationscount;
+            rep.terminationtype = state.repterminationtype;
+            rep.nfunc = state.repnfunc;
+            rep.njac = state.repnjac;
+            rep.ngrad = state.repngrad;
+            rep.nhess = state.repnhess;
+            rep.ncholesky = state.repncholesky;
+        }
+
+
+        /*************************************************************************
+        Prepare internal structures (except for RComm).
+
+        Note: M must be zero for FGH mode, non-zero for FJ/FGJ mode.
+        *************************************************************************/
+        private static void lmprepare(int n,
+            int m,
+            bool havegrad,
+            ref lmstate state)
+        {
+            state.repiterationscount = 0;
+            state.repterminationtype = 0;
+            state.repnfunc = 0;
+            state.repnjac = 0;
+            state.repngrad = 0;
+            state.repnhess = 0;
+            state.repncholesky = 0;
+            if( n<0 | m<0 )
+            {
+                return;
+            }
+            if( havegrad )
+            {
+                state.g = new double[n-1+1];
+            }
+            if( m!=0 )
+            {
+                state.j = new double[m-1+1, n-1+1];
+                state.fi = new double[m-1+1];
+                state.h = new double[0+1, 0+1];
+            }
+            else
+            {
+                state.j = new double[0+1, 0+1];
+                state.fi = new double[0+1];
+                state.h = new double[n-1+1, n-1+1];
+            }
+            state.x = new double[n-1+1];
+            state.rawmodel = new double[n-1+1, n-1+1];
+            state.model = new double[n-1+1, n-1+1];
+            state.xbase = new double[n-1+1];
+            state.xprec = new double[n-1+1];
+            state.gbase = new double[n-1+1];
+            state.xdir = new double[n-1+1];
+            state.work = new double[Math.Max(n, m)+1];
+        }
+
+
+        /*************************************************************************
+        Clears request fileds (to be sure that we don't forgot to clear something)
+        *************************************************************************/
+        private static void lmclearrequestfields(ref lmstate state)
+        {
+            state.needf = false;
+            state.needfg = false;
+            state.needfgh = false;
+            state.needfij = false;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlpbase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlpbase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlpbase.cs	(revision 2645)
@@ -0,0 +1,3571 @@
+/*************************************************************************
+Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class mlpbase
+    {
+        public struct multilayerperceptron
+        {
+            public int[] structinfo;
+            public double[] weights;
+            public double[] columnmeans;
+            public double[] columnsigmas;
+            public double[] neurons;
+            public double[] dfdnet;
+            public double[] derror;
+            public double[] x;
+            public double[] y;
+            public double[,] chunks;
+            public double[] nwbuf;
+        };
+
+
+
+
+        public const int mlpvnum = 7;
+        public const int nfieldwidth = 4;
+        public const int chunksize = 32;
+
+
+        /*************************************************************************
+        Creates  neural  network  with  NIn  inputs,  NOut outputs, without hidden
+        layers, with linear output layer. Network weights are  filled  with  small
+        random values.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreate0(int nin,
+            int nout,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+
+            layerscount = 1+2;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+        }
+
+
+        /*************************************************************************
+        Same  as  MLPCreate0,  but  with  one  hidden  layer  (NHid  neurons) with
+        non-linear activation function. Output layer is linear.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreate1(int nin,
+            int nhid,
+            int nout,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+
+            layerscount = 1+3+2;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreate0, but with two hidden layers (NHid1 and  NHid2  neurons)
+        with non-linear activation function. Output layer is linear.
+         $ALL
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreate2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+
+            layerscount = 1+3+3+2;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid2, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+        }
+
+
+        /*************************************************************************
+        Creates  neural  network  with  NIn  inputs,  NOut outputs, without hidden
+        layers with non-linear output layer. Network weights are filled with small
+        random values.
+
+        Activation function of the output layer takes values:
+
+            (B, +INF), if D>=0
+
+        or
+
+            (-INF, B), if D<0.
+
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreateb0(int nin,
+            int nout,
+            double b,
+            double d,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+            int i = 0;
+
+            layerscount = 1+3;
+            if( (double)(d)>=(double)(0) )
+            {
+                d = 1;
+            }
+            else
+            {
+                d = -1;
+            }
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(3, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+            
+            //
+            // Turn on ouputs shift/scaling.
+            //
+            for(i=nin; i<=nin+nout-1; i++)
+            {
+                network.columnmeans[i] = b;
+                network.columnsigmas[i] = d;
+            }
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreateB0 but with non-linear hidden layer.
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreateb1(int nin,
+            int nhid,
+            int nout,
+            double b,
+            double d,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+            int i = 0;
+
+            layerscount = 1+3+3;
+            if( (double)(d)>=(double)(0) )
+            {
+                d = 1;
+            }
+            else
+            {
+                d = -1;
+            }
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(3, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+            
+            //
+            // Turn on ouputs shift/scaling.
+            //
+            for(i=nin; i<=nin+nout-1; i++)
+            {
+                network.columnmeans[i] = b;
+                network.columnsigmas[i] = d;
+            }
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreateB0 but with two non-linear hidden layers.
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreateb2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            double b,
+            double d,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+            int i = 0;
+
+            layerscount = 1+3+3+3;
+            if( (double)(d)>=(double)(0) )
+            {
+                d = 1;
+            }
+            else
+            {
+                d = -1;
+            }
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid2, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(3, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+            
+            //
+            // Turn on ouputs shift/scaling.
+            //
+            for(i=nin; i<=nin+nout-1; i++)
+            {
+                network.columnmeans[i] = b;
+                network.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].
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreater0(int nin,
+            int nout,
+            double a,
+            double b,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+            int i = 0;
+
+            layerscount = 1+3;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+            
+            //
+            // Turn on outputs shift/scaling.
+            //
+            for(i=nin; i<=nin+nout-1; i++)
+            {
+                network.columnmeans[i] = 0.5*(a+b);
+                network.columnsigmas[i] = 0.5*(a-b);
+            }
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreateR0, but with non-linear hidden layer.
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreater1(int nin,
+            int nhid,
+            int nout,
+            double a,
+            double b,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+            int i = 0;
+
+            layerscount = 1+3+3;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+            
+            //
+            // Turn on outputs shift/scaling.
+            //
+            for(i=nin; i<=nin+nout-1; i++)
+            {
+                network.columnmeans[i] = 0.5*(a+b);
+                network.columnsigmas[i] = 0.5*(a-b);
+            }
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreateR0, but with two non-linear hidden layers.
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreater2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            double a,
+            double b,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+            int i = 0;
+
+            layerscount = 1+3+3+3;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid2, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, false, ref network);
+            
+            //
+            // Turn on outputs shift/scaling.
+            //
+            for(i=nin; i<=nin+nout-1; i++)
+            {
+                network.columnmeans[i] = 0.5*(a+b);
+                network.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).
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreatec0(int nin,
+            int nout,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+
+            System.Diagnostics.Debug.Assert(nout>=2, "MLPCreateC0: NOut<2!");
+            layerscount = 1+2+1;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout-1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addzerolayer(ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, true, ref network);
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreateC0, but with one non-linear hidden layer.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreatec1(int nin,
+            int nhid,
+            int nout,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+
+            System.Diagnostics.Debug.Assert(nout>=2, "MLPCreateC1: NOut<2!");
+            layerscount = 1+3+2+1;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout-1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addzerolayer(ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, true, ref network);
+        }
+
+
+        /*************************************************************************
+        Same as MLPCreateC0, but with two non-linear hidden layers.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcreatec2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            ref multilayerperceptron network)
+        {
+            int[] lsizes = new int[0];
+            int[] ltypes = new int[0];
+            int[] lconnfirst = new int[0];
+            int[] lconnlast = new int[0];
+            int layerscount = 0;
+            int lastproc = 0;
+
+            System.Diagnostics.Debug.Assert(nout>=2, "MLPCreateC2: NOut<2!");
+            layerscount = 1+3+3+2+1;
+            
+            //
+            // Allocate arrays
+            //
+            lsizes = new int[layerscount-1+1];
+            ltypes = new int[layerscount-1+1];
+            lconnfirst = new int[layerscount-1+1];
+            lconnlast = new int[layerscount-1+1];
+            
+            //
+            // Layers
+            //
+            addinputlayer(nin, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nhid2, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addactivationlayer(1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addbiasedsummatorlayer(nout-1, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            addzerolayer(ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, ref lastproc);
+            
+            //
+            // Create
+            //
+            mlpcreate(nin, nout, ref lsizes, ref ltypes, ref lconnfirst, ref lconnlast, layerscount, true, ref network);
+        }
+
+
+        /*************************************************************************
+        Copying of neural network
+
+        INPUT PARAMETERS:
+            Network1 -   original
+
+        OUTPUT PARAMETERS:
+            Network2 -   copy
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpcopy(ref multilayerperceptron network1,
+            ref multilayerperceptron network2)
+        {
+            int i = 0;
+            int ssize = 0;
+            int ntotal = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            int i_ = 0;
+
+            
+            //
+            // Unload info
+            //
+            ssize = network1.structinfo[0];
+            nin = network1.structinfo[1];
+            nout = network1.structinfo[2];
+            ntotal = network1.structinfo[3];
+            wcount = network1.structinfo[4];
+            
+            //
+            // Allocate space
+            //
+            network2.structinfo = new int[ssize-1+1];
+            network2.weights = new double[wcount-1+1];
+            if( mlpissoftmax(ref network1) )
+            {
+                network2.columnmeans = new double[nin-1+1];
+                network2.columnsigmas = new double[nin-1+1];
+            }
+            else
+            {
+                network2.columnmeans = new double[nin+nout-1+1];
+                network2.columnsigmas = new double[nin+nout-1+1];
+            }
+            network2.neurons = new double[ntotal-1+1];
+            network2.chunks = new double[3*ntotal+1, chunksize-1+1];
+            network2.nwbuf = new double[Math.Max(wcount, 2*nout)-1+1];
+            network2.dfdnet = new double[ntotal-1+1];
+            network2.x = new double[nin-1+1];
+            network2.y = new double[nout-1+1];
+            network2.derror = new double[ntotal-1+1];
+            
+            //
+            // Copy
+            //
+            for(i=0; i<=ssize-1; i++)
+            {
+                network2.structinfo[i] = network1.structinfo[i];
+            }
+            for(i_=0; i_<=wcount-1;i_++)
+            {
+                network2.weights[i_] = network1.weights[i_];
+            }
+            if( mlpissoftmax(ref network1) )
+            {
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    network2.columnmeans[i_] = network1.columnmeans[i_];
+                }
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    network2.columnsigmas[i_] = network1.columnsigmas[i_];
+                }
+            }
+            else
+            {
+                for(i_=0; i_<=nin+nout-1;i_++)
+                {
+                    network2.columnmeans[i_] = network1.columnmeans[i_];
+                }
+                for(i_=0; i_<=nin+nout-1;i_++)
+                {
+                    network2.columnsigmas[i_] = network1.columnsigmas[i_];
+                }
+            }
+            for(i_=0; i_<=ntotal-1;i_++)
+            {
+                network2.neurons[i_] = network1.neurons[i_];
+            }
+            for(i_=0; i_<=ntotal-1;i_++)
+            {
+                network2.dfdnet[i_] = network1.dfdnet[i_];
+            }
+            for(i_=0; i_<=nin-1;i_++)
+            {
+                network2.x[i_] = network1.x[i_];
+            }
+            for(i_=0; i_<=nout-1;i_++)
+            {
+                network2.y[i_] = network1.y[i_];
+            }
+            for(i_=0; i_<=ntotal-1;i_++)
+            {
+                network2.derror[i_] = network1.derror[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of MultiLayerPerceptron strucure
+
+        INPUT PARAMETERS:
+            Network -   original
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which stores network,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 29.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpserialize(ref multilayerperceptron network,
+            ref double[] ra,
+            ref int rlen)
+        {
+            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;
+
+            
+            //
+            // Unload info
+            //
+            ssize = network.structinfo[0];
+            nin = network.structinfo[1];
+            nout = network.structinfo[2];
+            ntotal = network.structinfo[3];
+            wcount = network.structinfo[4];
+            if( mlpissoftmax(ref 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;
+            ra = new double[rlen-1+1];
+            ra[0] = rlen;
+            ra[1] = mlpvnum;
+            ra[2] = ssize;
+            offs = 3;
+            for(i=0; i<=ssize-1; i++)
+            {
+                ra[offs+i] = network.structinfo[i];
+            }
+            offs = offs+ssize;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+wcount-1;i_++)
+            {
+                ra[i_] = network.weights[i_+i1_];
+            }
+            offs = offs+wcount;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+sigmalen-1;i_++)
+            {
+                ra[i_] = network.columnmeans[i_+i1_];
+            }
+            offs = offs+sigmalen;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+sigmalen-1;i_++)
+            {
+                ra[i_] = network.columnsigmas[i_+i1_];
+            }
+            offs = offs+sigmalen;
+        }
+
+
+        /*************************************************************************
+        Unserialization of MultiLayerPerceptron strucure
+
+        INPUT PARAMETERS:
+            RA      -   real array which stores network
+
+        OUTPUT PARAMETERS:
+            Network -   restored network
+
+          -- ALGLIB --
+             Copyright 29.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpunserialize(ref double[] ra,
+            ref multilayerperceptron network)
+        {
+            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;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[1])==mlpvnum, "MLPUnserialize: incorrect array!");
+            
+            //
+            // Unload StructInfo from IA
+            //
+            offs = 3;
+            ssize = (int)Math.Round(ra[2]);
+            network.structinfo = new int[ssize-1+1];
+            for(i=0; i<=ssize-1; i++)
+            {
+                network.structinfo[i] = (int)Math.Round(ra[offs+i]);
+            }
+            offs = offs+ssize;
+            
+            //
+            // Unload info from StructInfo
+            //
+            ssize = network.structinfo[0];
+            nin = network.structinfo[1];
+            nout = network.structinfo[2];
+            ntotal = network.structinfo[3];
+            wcount = network.structinfo[4];
+            if( network.structinfo[6]==0 )
+            {
+                sigmalen = nin+nout;
+            }
+            else
+            {
+                sigmalen = nin;
+            }
+            
+            //
+            // Allocate space for other fields
+            //
+            network.weights = new double[wcount-1+1];
+            network.columnmeans = new double[sigmalen-1+1];
+            network.columnsigmas = new double[sigmalen-1+1];
+            network.neurons = new double[ntotal-1+1];
+            network.chunks = new double[3*ntotal+1, chunksize-1+1];
+            network.nwbuf = new double[Math.Max(wcount, 2*nout)-1+1];
+            network.dfdnet = new double[ntotal-1+1];
+            network.x = new double[nin-1+1];
+            network.y = new double[nout-1+1];
+            network.derror = new double[ntotal-1+1];
+            
+            //
+            // Copy parameters from RA
+            //
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=wcount-1;i_++)
+            {
+                network.weights[i_] = ra[i_+i1_];
+            }
+            offs = offs+wcount;
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=sigmalen-1;i_++)
+            {
+                network.columnmeans[i_] = ra[i_+i1_];
+            }
+            offs = offs+sigmalen;
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=sigmalen-1;i_++)
+            {
+                network.columnsigmas[i_] = ra[i_+i1_];
+            }
+            offs = offs+sigmalen;
+        }
+
+
+        /*************************************************************************
+        Randomization of neural network weights
+
+          -- ALGLIB --
+             Copyright 06.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlprandomize(ref multilayerperceptron network)
+        {
+            int i = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            for(i=0; i<=wcount-1; i++)
+            {
+                network.weights[i] = AP.Math.RandomReal()-0.5;
+            }
+        }
+
+
+        /*************************************************************************
+        Randomization of neural network weights and standartisator
+
+          -- ALGLIB --
+             Copyright 10.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlprandomizefull(ref multilayerperceptron network)
+        {
+            int i = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            int ntotal = 0;
+            int istart = 0;
+            int offs = 0;
+            int ntype = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            ntotal = network.structinfo[3];
+            istart = network.structinfo[5];
+            
+            //
+            // Process network
+            //
+            for(i=0; i<=wcount-1; i++)
+            {
+                network.weights[i] = AP.Math.RandomReal()-0.5;
+            }
+            for(i=0; i<=nin-1; i++)
+            {
+                network.columnmeans[i] = 2*AP.Math.RandomReal()-1;
+                network.columnsigmas[i] = 1.5*AP.Math.RandomReal()+0.5;
+            }
+            if( !mlpissoftmax(ref network) )
+            {
+                for(i=0; i<=nout-1; i++)
+                {
+                    offs = istart+(ntotal-nout+i)*nfieldwidth;
+                    ntype = network.structinfo[offs+0];
+                    if( ntype==0 )
+                    {
+                        
+                        //
+                        // Shifts are changed only for linear outputs neurons
+                        //
+                        network.columnmeans[nin+i] = 2*AP.Math.RandomReal()-1;
+                    }
+                    if( ntype==0 | ntype==3 )
+                    {
+                        
+                        //
+                        // Scales are changed only for linear or bounded outputs neurons.
+                        // Note that scale randomization preserves sign.
+                        //
+                        network.columnsigmas[nin+i] = Math.Sign(network.columnsigmas[nin+i])*(1.5*AP.Math.RandomReal()+0.5);
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 30.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpinitpreprocessor(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize)
+        {
+            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[] means = new double[0];
+            double[] sigmas = new double[0];
+            double s = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            ntotal = network.structinfo[3];
+            istart = network.structinfo[5];
+            
+            //
+            // Means/Sigmas
+            //
+            if( mlpissoftmax(ref network) )
+            {
+                jmax = nin-1;
+            }
+            else
+            {
+                jmax = nin+nout-1;
+            }
+            means = new double[jmax+1];
+            sigmas = new double[jmax+1];
+            for(j=0; j<=jmax; j++)
+            {
+                means[j] = 0;
+                for(i=0; i<=ssize-1; i++)
+                {
+                    means[j] = means[j]+xy[i,j];
+                }
+                means[j] = means[j]/ssize;
+                sigmas[j] = 0;
+                for(i=0; i<=ssize-1; i++)
+                {
+                    sigmas[j] = sigmas[j]+AP.Math.Sqr(xy[i,j]-means[j]);
+                }
+                sigmas[j] = Math.Sqrt(sigmas[j]/ssize);
+            }
+            
+            //
+            // Inputs
+            //
+            for(i=0; i<=nin-1; i++)
+            {
+                network.columnmeans[i] = means[i];
+                network.columnsigmas[i] = sigmas[i];
+                if( (double)(network.columnsigmas[i])==(double)(0) )
+                {
+                    network.columnsigmas[i] = 1;
+                }
+            }
+            
+            //
+            // Outputs
+            //
+            if( !mlpissoftmax(ref network) )
+            {
+                for(i=0; i<=nout-1; i++)
+                {
+                    offs = istart+(ntotal-nout+i)*nfieldwidth;
+                    ntype = network.structinfo[offs+0];
+                    
+                    //
+                    // Linear outputs
+                    //
+                    if( ntype==0 )
+                    {
+                        network.columnmeans[nin+i] = means[nin+i];
+                        network.columnsigmas[nin+i] = sigmas[nin+i];
+                        if( (double)(network.columnsigmas[nin+i])==(double)(0) )
+                        {
+                            network.columnsigmas[nin+i] = 1;
+                        }
+                    }
+                    
+                    //
+                    // Bounded outputs (half-interval)
+                    //
+                    if( ntype==3 )
+                    {
+                        s = means[nin+i]-network.columnmeans[nin+i];
+                        if( (double)(s)==(double)(0) )
+                        {
+                            s = Math.Sign(network.columnsigmas[nin+i]);
+                        }
+                        if( (double)(s)==(double)(0) )
+                        {
+                            s = 1.0;
+                        }
+                        network.columnsigmas[nin+i] = Math.Sign(network.columnsigmas[nin+i])*Math.Abs(s);
+                        if( (double)(network.columnsigmas[nin+i])==(double)(0) )
+                        {
+                            network.columnsigmas[nin+i] = 1;
+                        }
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns information about initialized network: number of inputs, outputs,
+        weights.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpproperties(ref multilayerperceptron network,
+            ref int nin,
+            ref int nout,
+            ref int wcount)
+        {
+            nin = network.structinfo[1];
+            nout = network.structinfo[2];
+            wcount = network.structinfo[4];
+        }
+
+
+        /*************************************************************************
+        Tells whether network is SOFTMAX-normalized (i.e. classifier) or not.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool mlpissoftmax(ref multilayerperceptron network)
+        {
+            bool result = new bool();
+
+            result = network.structinfo[6]==1;
+            return result;
+        }
+
+
+        /*************************************************************************
+        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.
+                        Subroutine does not allocate memory for this vector, it is
+                        responsibility of a caller to allocate it. Array  must  be
+                        at least [0..NOut-1].
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpprocess(ref multilayerperceptron network,
+            ref double[] x,
+            ref double[] y)
+        {
+            mlpinternalprocessvector(ref network.structinfo, ref network.weights, ref network.columnmeans, ref network.columnsigmas, ref network.neurons, ref network.dfdnet, ref x, ref y);
+        }
+
+
+        /*************************************************************************
+        Error function for neural network, internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlperror(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize)
+        {
+            double result = 0;
+            int i = 0;
+            int k = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double e = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            result = 0;
+            for(i=0; i<=ssize-1; i++)
+            {
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    network.x[i_] = xy[i,i_];
+                }
+                mlpprocess(ref network, ref network.x, ref network.y);
+                if( mlpissoftmax(ref network) )
+                {
+                    
+                    //
+                    // class labels outputs
+                    //
+                    k = (int)Math.Round(xy[i,nin]);
+                    if( k>=0 & k<nout )
+                    {
+                        network.y[k] = network.y[k]-1;
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // real outputs
+                    //
+                    i1_ = (nin) - (0);
+                    for(i_=0; i_<=nout-1;i_++)
+                    {
+                        network.y[i_] = network.y[i_] - xy[i,i_+i1_];
+                    }
+                }
+                e = 0.0;
+                for(i_=0; i_<=nout-1;i_++)
+                {
+                    e += network.y[i_]*network.y[i_];
+                }
+                result = result+e/2;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Natural error function for neural network, internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlperrorn(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double e = 0;
+            double t = 0;
+            double z = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            result = 0;
+            for(i=0; i<=ssize-1; i++)
+            {
+                
+                //
+                // Process vector
+                //
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    network.x[i_] = xy[i,i_];
+                }
+                mlpprocess(ref network, ref network.x, ref network.y);
+                
+                //
+                // Update error function
+                //
+                if( network.structinfo[6]==0 )
+                {
+                    
+                    //
+                    // Least squares error function
+                    //
+                    i1_ = (nin) - (0);
+                    for(i_=0; i_<=nout-1;i_++)
+                    {
+                        network.y[i_] = network.y[i_] - xy[i,i_+i1_];
+                    }
+                    e = 0.0;
+                    for(i_=0; i_<=nout-1;i_++)
+                    {
+                        e += network.y[i_]*network.y[i_];
+                    }
+                    result = result+e/2;
+                }
+                else
+                {
+                    
+                    //
+                    // Cross-entropy error function
+                    //
+                    k = (int)Math.Round(xy[i,nin]);
+                    if( k>=0 & k<nout )
+                    {
+                        result = result+safecrossentropy(1, network.y[k]);
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Classification error
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static int mlpclserror(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize)
+        {
+            int result = 0;
+            int i = 0;
+            int j = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double[] workx = new double[0];
+            double[] worky = new double[0];
+            int nn = 0;
+            int ns = 0;
+            int nmax = 0;
+            int i_ = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            workx = new double[nin-1+1];
+            worky = new double[nout-1+1];
+            result = 0;
+            for(i=0; i<=ssize-1; i++)
+            {
+                
+                //
+                // Process
+                //
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    workx[i_] = xy[i,i_];
+                }
+                mlpprocess(ref network, ref workx, ref worky);
+                
+                //
+                // Network version of the answer
+                //
+                nmax = 0;
+                for(j=0; j<=nout-1; j++)
+                {
+                    if( (double)(worky[j])>(double)(worky[nmax]) )
+                    {
+                        nmax = j;
+                    }
+                }
+                nn = nmax;
+                
+                //
+                // Right answer
+                //
+                if( mlpissoftmax(ref network) )
+                {
+                    ns = (int)Math.Round(xy[i,nin]);
+                }
+                else
+                {
+                    nmax = 0;
+                    for(j=0; j<=nout-1; j++)
+                    {
+                        if( (double)(xy[i,nin+j])>(double)(xy[i,nin+nmax]) )
+                        {
+                            nmax = j;
+                        }
+                    }
+                    ns = nmax;
+                }
+                
+                //
+                // compare
+                //
+                if( nn!=ns )
+                {
+                    result = result+1;
+                }
+            }
+            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.
+
+          -- ALGLIB --
+             Copyright 25.12.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlprelclserror(ref multilayerperceptron network,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+
+            result = (double)(mlpclserror(ref network, ref xy, npoints))/(double)(npoints);
+            return result;
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 08.01.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpavgce(ref multilayerperceptron network,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+
+            if( mlpissoftmax(ref network) )
+            {
+                mlpproperties(ref network, ref nin, ref nout, ref wcount);
+                result = mlperrorn(ref network, ref xy, npoints)/(npoints*Math.Log(2));
+            }
+            else
+            {
+                result = 0;
+            }
+            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.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlprmserror(ref multilayerperceptron network,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            result = Math.Sqrt(2*mlperror(ref network, ref xy, npoints)/(npoints*nout));
+            return result;
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 11.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpavgerror(ref multilayerperceptron network,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            int i_ = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            result = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    network.x[i_] = xy[i,i_];
+                }
+                mlpprocess(ref network, ref network.x, ref network.y);
+                if( mlpissoftmax(ref network) )
+                {
+                    
+                    //
+                    // class labels
+                    //
+                    k = (int)Math.Round(xy[i,nin]);
+                    for(j=0; j<=nout-1; j++)
+                    {
+                        if( j==k )
+                        {
+                            result = result+Math.Abs(1-network.y[j]);
+                        }
+                        else
+                        {
+                            result = result+Math.Abs(network.y[j]);
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // real outputs
+                    //
+                    for(j=0; j<=nout-1; j++)
+                    {
+                        result = result+Math.Abs(xy[i,nin+j]-network.y[j]);
+                    }
+                }
+            }
+            result = result/(npoints*nout);
+            return result;
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 11.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpavgrelerror(ref multilayerperceptron network,
+            ref double[,] xy,
+            int npoints)
+        {
+            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;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            result = 0;
+            k = 0;
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=nin-1;i_++)
+                {
+                    network.x[i_] = xy[i,i_];
+                }
+                mlpprocess(ref network, ref network.x, ref network.y);
+                if( mlpissoftmax(ref network) )
+                {
+                    
+                    //
+                    // class labels
+                    //
+                    lk = (int)Math.Round(xy[i,nin]);
+                    for(j=0; j<=nout-1; j++)
+                    {
+                        if( j==lk )
+                        {
+                            result = result+Math.Abs(1-network.y[j]);
+                            k = k+1;
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // real outputs
+                    //
+                    for(j=0; j<=nout-1; j++)
+                    {
+                        if( (double)(xy[i,nin+j])!=(double)(0) )
+                        {
+                            result = result+Math.Abs(xy[i,nin+j]-network.y[j])/Math.Abs(xy[i,nin+j]);
+                            k = k+1;
+                        }
+                    }
+                }
+            }
+            if( k!=0 )
+            {
+                result = result/k;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Gradient calculation. Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpgrad(ref multilayerperceptron network,
+            ref double[] x,
+            ref double[] desiredy,
+            ref double e,
+            ref double[] grad)
+        {
+            int i = 0;
+            int nout = 0;
+            int ntotal = 0;
+
+            
+            //
+            // Prepare dError/dOut, internal structures
+            //
+            mlpprocess(ref network, ref x, ref network.y);
+            nout = network.structinfo[2];
+            ntotal = network.structinfo[3];
+            e = 0;
+            for(i=0; i<=ntotal-1; i++)
+            {
+                network.derror[i] = 0;
+            }
+            for(i=0; i<=nout-1; i++)
+            {
+                network.derror[ntotal-nout+i] = network.y[i]-desiredy[i];
+                e = e+AP.Math.Sqr(network.y[i]-desiredy[i])/2;
+            }
+            
+            //
+            // gradient
+            //
+            mlpinternalcalculategradient(ref network, ref network.neurons, ref network.weights, ref network.derror, ref grad, false);
+        }
+
+
+        /*************************************************************************
+        Gradient calculation (natural error function). Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpgradn(ref multilayerperceptron network,
+            ref double[] x,
+            ref double[] desiredy,
+            ref double e,
+            ref double[] grad)
+        {
+            double s = 0;
+            int i = 0;
+            int nout = 0;
+            int ntotal = 0;
+
+            
+            //
+            // Prepare dError/dOut, internal structures
+            //
+            mlpprocess(ref network, ref x, ref network.y);
+            nout = network.structinfo[2];
+            ntotal = network.structinfo[3];
+            for(i=0; i<=ntotal-1; i++)
+            {
+                network.derror[i] = 0;
+            }
+            e = 0;
+            if( network.structinfo[6]==0 )
+            {
+                
+                //
+                // Regression network, least squares
+                //
+                for(i=0; i<=nout-1; i++)
+                {
+                    network.derror[ntotal-nout+i] = network.y[i]-desiredy[i];
+                    e = e+AP.Math.Sqr(network.y[i]-desiredy[i])/2;
+                }
+            }
+            else
+            {
+                
+                //
+                // Classification network, cross-entropy
+                //
+                s = 0;
+                for(i=0; i<=nout-1; i++)
+                {
+                    s = s+desiredy[i];
+                }
+                for(i=0; i<=nout-1; i++)
+                {
+                    network.derror[ntotal-nout+i] = s*network.y[i]-desiredy[i];
+                    e = e+safecrossentropy(desiredy[i], network.y[i]);
+                }
+            }
+            
+            //
+            // gradient
+            //
+            mlpinternalcalculategradient(ref network, ref network.neurons, ref network.weights, ref network.derror, ref grad, true);
+        }
+
+
+        /*************************************************************************
+        Batch gradient calculation. Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpgradbatch(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize,
+            ref double e,
+            ref double[] grad)
+        {
+            int i = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            for(i=0; i<=wcount-1; i++)
+            {
+                grad[i] = 0;
+            }
+            e = 0;
+            i = 0;
+            while( i<=ssize-1 )
+            {
+                mlpchunkedgradient(ref network, ref xy, i, Math.Min(ssize, i+chunksize)-i, ref e, ref grad, false);
+                i = i+chunksize;
+            }
+        }
+
+
+        /*************************************************************************
+        Batch gradient calculation (natural error function). Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpgradnbatch(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize,
+            ref double e,
+            ref double[] grad)
+        {
+            int i = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            for(i=0; i<=wcount-1; i++)
+            {
+                grad[i] = 0;
+            }
+            e = 0;
+            i = 0;
+            while( i<=ssize-1 )
+            {
+                mlpchunkedgradient(ref network, ref xy, i, Math.Min(ssize, i+chunksize)-i, ref e, ref grad, true);
+                i = i+chunksize;
+            }
+        }
+
+
+        /*************************************************************************
+        Batch Hessian calculation (natural error function) using R-algorithm.
+        Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 26.01.2008 by Bochkanov Sergey.
+             
+             Hessian calculation based on R-algorithm described in
+             "Fast Exact Multiplication by the Hessian",
+             B. A. Pearlmutter,
+             Neural Computation, 1994.
+        *************************************************************************/
+        public static void mlphessiannbatch(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize,
+            ref double e,
+            ref double[] grad,
+            ref double[,] h)
+        {
+            mlphessianbatchinternal(ref network, ref xy, ssize, true, ref e, ref grad, ref h);
+        }
+
+
+        /*************************************************************************
+        Batch Hessian calculation using R-algorithm.
+        Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 26.01.2008 by Bochkanov Sergey.
+
+             Hessian calculation based on R-algorithm described in
+             "Fast Exact Multiplication by the Hessian",
+             B. A. Pearlmutter,
+             Neural Computation, 1994.
+        *************************************************************************/
+        public static void mlphessianbatch(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize,
+            ref double e,
+            ref double[] grad,
+            ref double[,] h)
+        {
+            mlphessianbatchinternal(ref network, ref xy, ssize, false, ref e, ref grad, ref h);
+        }
+
+
+        /*************************************************************************
+        Internal subroutine, shouldn't be called by user.
+        *************************************************************************/
+        public static void mlpinternalprocessvector(ref int[] structinfo,
+            ref double[] weights,
+            ref double[] columnmeans,
+            ref double[] columnsigmas,
+            ref double[] neurons,
+            ref double[] dfdnet,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            int j = 0;
+            int n1 = 0;
+            int n2 = 0;
+            int w1 = 0;
+            int w2 = 0;
+            int ntotal = 0;
+            int nin = 0;
+            int nout = 0;
+            int istart = 0;
+            int offs = 0;
+            double net = 0;
+            double e = 0;
+            double f = 0;
+            double df = 0;
+            double d2f = 0;
+            double mx = 0;
+            bool perr = new bool();
+            int i_ = 0;
+            int i1_ = 0;
+
+            
+            //
+            // Read network geometry
+            //
+            nin = structinfo[1];
+            nout = structinfo[2];
+            ntotal = structinfo[3];
+            istart = structinfo[5];
+            
+            //
+            // Inputs standartisation and putting in the network
+            //
+            for(i=0; i<=nin-1; i++)
+            {
+                if( (double)(columnsigmas[i])!=(double)(0) )
+                {
+                    neurons[i] = (x[i]-columnmeans[i])/columnsigmas[i];
+                }
+                else
+                {
+                    neurons[i] = x[i]-columnmeans[i];
+                }
+            }
+            
+            //
+            // Process network
+            //
+            for(i=0; i<=ntotal-1; i++)
+            {
+                offs = istart+i*nfieldwidth;
+                if( structinfo[offs+0]>0 )
+                {
+                    
+                    //
+                    // Activation function
+                    //
+                    mlpactivationfunction(neurons[structinfo[offs+2]], structinfo[offs+0], ref f, ref df, ref d2f);
+                    neurons[i] = f;
+                    dfdnet[i] = df;
+                }
+                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;
+                    for(i_=w1; i_<=w2;i_++)
+                    {
+                        net += weights[i_]*neurons[i_+i1_];
+                    }
+                    neurons[i] = net;
+                    dfdnet[i] = 1.0;
+                }
+                if( structinfo[offs+0]<0 )
+                {
+                    perr = true;
+                    if( structinfo[offs+0]==-2 )
+                    {
+                        
+                        //
+                        // input neuron, left unchanged
+                        //
+                        perr = false;
+                    }
+                    if( structinfo[offs+0]==-3 )
+                    {
+                        
+                        //
+                        // "-1" neuron
+                        //
+                        neurons[i] = -1;
+                        perr = false;
+                    }
+                    if( structinfo[offs+0]==-4 )
+                    {
+                        
+                        //
+                        // "0" neuron
+                        //
+                        neurons[i] = 0;
+                        perr = false;
+                    }
+                    System.Diagnostics.Debug.Assert(!perr, "MLPInternalProcessVector: internal error - unknown neuron type!");
+                }
+            }
+            
+            //
+            // Extract result
+            //
+            i1_ = (ntotal-nout) - (0);
+            for(i_=0; i_<=nout-1;i_++)
+            {
+                y[i_] = neurons[i_+i1_];
+            }
+            
+            //
+            // Softmax post-processing or standardisation if needed
+            //
+            System.Diagnostics.Debug.Assert(structinfo[6]==0 | structinfo[6]==1, "MLPInternalProcessVector: unknown normalization type!");
+            if( structinfo[6]==1 )
+            {
+                
+                //
+                // Softmax
+                //
+                mx = y[0];
+                for(i=1; i<=nout-1; i++)
+                {
+                    mx = Math.Max(mx, y[i]);
+                }
+                net = 0;
+                for(i=0; i<=nout-1; i++)
+                {
+                    y[i] = Math.Exp(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];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine: adding new input layer to network
+        *************************************************************************/
+        private static void addinputlayer(int ncount,
+            ref int[] lsizes,
+            ref int[] ltypes,
+            ref int[] lconnfirst,
+            ref int[] lconnlast,
+            ref int lastproc)
+        {
+            lsizes[0] = ncount;
+            ltypes[0] = -2;
+            lconnfirst[0] = 0;
+            lconnlast[0] = 0;
+            lastproc = 0;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine: adding new summator layer to network
+        *************************************************************************/
+        private static void addbiasedsummatorlayer(int ncount,
+            ref int[] lsizes,
+            ref int[] ltypes,
+            ref int[] lconnfirst,
+            ref int[] lconnlast,
+            ref int lastproc)
+        {
+            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
+        *************************************************************************/
+        private static void addactivationlayer(int functype,
+            ref int[] lsizes,
+            ref int[] ltypes,
+            ref int[] lconnfirst,
+            ref int[] lconnlast,
+            ref int lastproc)
+        {
+            System.Diagnostics.Debug.Assert(functype>0, "AddActivationLayer: incorrect function type");
+            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
+        *************************************************************************/
+        private static void addzerolayer(ref int[] lsizes,
+            ref int[] ltypes,
+            ref int[] lconnfirst,
+            ref int[] lconnlast,
+            ref int lastproc)
+        {
+            lsizes[lastproc+1] = 1;
+            ltypes[lastproc+1] = -4;
+            lconnfirst[lastproc+1] = 0;
+            lconnlast[lastproc+1] = 0;
+            lastproc = lastproc+1;
+        }
+
+
+        /*************************************************************************
+        Internal subroutine.
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        private static void mlpcreate(int nin,
+            int nout,
+            ref int[] lsizes,
+            ref int[] ltypes,
+            ref int[] lconnfirst,
+            ref int[] lconnlast,
+            int layerscount,
+            bool isclsnet,
+            ref multilayerperceptron network)
+        {
+            int i = 0;
+            int j = 0;
+            int ssize = 0;
+            int ntotal = 0;
+            int wcount = 0;
+            int offs = 0;
+            int nprocessed = 0;
+            int wallocated = 0;
+            int[] localtemp = new int[0];
+            int[] lnfirst = new int[0];
+            int[] lnsyn = new int[0];
+
+            
+            //
+            // Check
+            //
+            System.Diagnostics.Debug.Assert(layerscount>0, "MLPCreate: wrong parameters!");
+            System.Diagnostics.Debug.Assert(ltypes[0]==-2, "MLPCreate: wrong LTypes[0] (must be -2)!");
+            for(i=0; i<=layerscount-1; i++)
+            {
+                System.Diagnostics.Debug.Assert(lsizes[i]>0, "MLPCreate: wrong LSizes!");
+                System.Diagnostics.Debug.Assert(lconnfirst[i]>=0 & (lconnfirst[i]<i | i==0), "MLPCreate: wrong LConnFirst!");
+                System.Diagnostics.Debug.Assert(lconnlast[i]>=lconnfirst[i] & (lconnlast[i]<i | i==0), "MLPCreate: wrong LConnLast!");
+            }
+            
+            //
+            // Build network geometry
+            //
+            lnfirst = new int[layerscount-1+1];
+            lnsyn = new int[layerscount-1+1];
+            ntotal = 0;
+            wcount = 0;
+            for(i=0; i<=layerscount-1; i++)
+            {
+                
+                //
+                // Analyze connections.
+                // This code must throw an assertion in case of unknown LTypes[I]
+                //
+                lnsyn[i] = -1;
+                if( ltypes[i]>=0 )
+                {
+                    lnsyn[i] = 0;
+                    for(j=lconnfirst[i]; j<=lconnlast[i]; j++)
+                    {
+                        lnsyn[i] = lnsyn[i]+lsizes[j];
+                    }
+                }
+                else
+                {
+                    if( ltypes[i]==-2 | ltypes[i]==-3 | ltypes[i]==-4 )
+                    {
+                        lnsyn[i] = 0;
+                    }
+                }
+                System.Diagnostics.Debug.Assert(lnsyn[i]>=0, "MLPCreate: internal error #0!");
+                
+                //
+                // Other info
+                //
+                lnfirst[i] = ntotal;
+                ntotal = ntotal+lsizes[i];
+                if( ltypes[i]==0 )
+                {
+                    wcount = wcount+lnsyn[i]*lsizes[i];
+                }
+            }
+            ssize = 7+ntotal*nfieldwidth;
+            
+            //
+            // Allocate
+            //
+            network.structinfo = new int[ssize-1+1];
+            network.weights = new double[wcount-1+1];
+            if( isclsnet )
+            {
+                network.columnmeans = new double[nin-1+1];
+                network.columnsigmas = new double[nin-1+1];
+            }
+            else
+            {
+                network.columnmeans = new double[nin+nout-1+1];
+                network.columnsigmas = new double[nin+nout-1+1];
+            }
+            network.neurons = new double[ntotal-1+1];
+            network.chunks = new double[3*ntotal+1, chunksize-1+1];
+            network.nwbuf = new double[Math.Max(wcount, 2*nout)-1+1];
+            network.dfdnet = new double[ntotal-1+1];
+            network.x = new double[nin-1+1];
+            network.y = new double[nout-1+1];
+            network.derror = new double[ntotal-1+1];
+            
+            //
+            // Fill structure: global info
+            //
+            network.structinfo[0] = ssize;
+            network.structinfo[1] = nin;
+            network.structinfo[2] = nout;
+            network.structinfo[3] = ntotal;
+            network.structinfo[4] = wcount;
+            network.structinfo[5] = 7;
+            if( isclsnet )
+            {
+                network.structinfo[6] = 1;
+            }
+            else
+            {
+                network.structinfo[6] = 0;
+            }
+            
+            //
+            // Fill structure: neuron connections
+            //
+            nprocessed = 0;
+            wallocated = 0;
+            for(i=0; i<=layerscount-1; i++)
+            {
+                for(j=0; j<=lsizes[i]-1; j++)
+                {
+                    offs = network.structinfo[5]+nprocessed*nfieldwidth;
+                    network.structinfo[offs+0] = ltypes[i];
+                    if( ltypes[i]==0 )
+                    {
+                        
+                        //
+                        // Adaptive summator:
+                        // * connections with weights to previous neurons
+                        //
+                        network.structinfo[offs+1] = lnsyn[i];
+                        network.structinfo[offs+2] = lnfirst[lconnfirst[i]];
+                        network.structinfo[offs+3] = wallocated;
+                        wallocated = wallocated+lnsyn[i];
+                        nprocessed = nprocessed+1;
+                    }
+                    if( ltypes[i]>0 )
+                    {
+                        
+                        //
+                        // Activation layer:
+                        // * each neuron connected to one (only one) of previous neurons.
+                        // * no weights
+                        //
+                        network.structinfo[offs+1] = 1;
+                        network.structinfo[offs+2] = lnfirst[lconnfirst[i]]+j;
+                        network.structinfo[offs+3] = -1;
+                        nprocessed = nprocessed+1;
+                    }
+                    if( ltypes[i]==-2 | ltypes[i]==-3 | ltypes[i]==-4 )
+                    {
+                        nprocessed = nprocessed+1;
+                    }
+                }
+            }
+            System.Diagnostics.Debug.Assert(wallocated==wcount, "MLPCreate: internal error #1!");
+            System.Diagnostics.Debug.Assert(nprocessed==ntotal, "MLPCreate: internal error #2!");
+            
+            //
+            // Fill weights by small random values
+            // Initialize means and sigmas
+            //
+            for(i=0; i<=wcount-1; i++)
+            {
+                network.weights[i] = AP.Math.RandomReal()-0.5;
+            }
+            for(i=0; i<=nin-1; i++)
+            {
+                network.columnmeans[i] = 0;
+                network.columnsigmas[i] = 1;
+            }
+            if( !isclsnet )
+            {
+                for(i=0; i<=nout-1; i++)
+                {
+                    network.columnmeans[nin+i] = 0;
+                    network.columnsigmas[nin+i] = 1;
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+
+          -- ALGLIB --
+             Copyright 04.11.2007 by Bochkanov Sergey
+        *************************************************************************/
+        private static void mlpactivationfunction(double net,
+            int k,
+            ref double f,
+            ref double df,
+            ref double d2f)
+        {
+            double net2 = 0;
+            double arg = 0;
+            double root = 0;
+            double r = 0;
+
+            f = 0;
+            df = 0;
+            if( k==1 )
+            {
+                
+                //
+                // TanH activation function
+                //
+                if( (double)(Math.Abs(net))<(double)(100) )
+                {
+                    f = Math.Tanh(net);
+                }
+                else
+                {
+                    f = Math.Sign(net);
+                }
+                df = 1-AP.Math.Sqr(f);
+                d2f = -(2*f*df);
+                return;
+            }
+            if( k==3 )
+            {
+                
+                //
+                // EX activation function
+                //
+                if( (double)(net)>=(double)(0) )
+                {
+                    net2 = net*net;
+                    arg = net2+1;
+                    root = Math.Sqrt(arg);
+                    f = net+root;
+                    r = net/root;
+                    df = 1+r;
+                    d2f = (root-net*r)/arg;
+                }
+                else
+                {
+                    f = Math.Exp(net);
+                    df = f;
+                    d2f = f;
+                }
+                return;
+            }
+            if( k==2 )
+            {
+                f = Math.Exp(-AP.Math.Sqr(net));
+                df = -(2*net*f);
+                d2f = -(2*(f+df*net));
+                return;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine for Hessian calculation.
+
+        WARNING!!! Unspeakable math far beyong human capabilities :)
+        *************************************************************************/
+        private static void mlphessianbatchinternal(ref multilayerperceptron network,
+            ref double[,] xy,
+            int ssize,
+            bool naturalerr,
+            ref double e,
+            ref double[] grad,
+            ref double[,] h)
+        {
+            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 = new bool();
+            double f = 0;
+            double df = 0;
+            double d2f = 0;
+            double deidyj = 0;
+            double mx = 0;
+            double net = 0;
+            double q = 0;
+            double z = 0;
+            double s2 = 0;
+            double expi = 0;
+            double expj = 0;
+            double[] x = new double[0];
+            double[] desiredy = new double[0];
+            double[] gt = new double[0];
+            double[] zeros = new double[0];
+            double[,] rx = new double[0,0];
+            double[,] ry = new double[0,0];
+            double[,] rdx = new double[0,0];
+            double[,] rdy = new double[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            ntotal = network.structinfo[3];
+            istart = network.structinfo[5];
+            
+            //
+            // Prepare
+            //
+            x = new double[nin-1+1];
+            desiredy = new double[nout-1+1];
+            zeros = new double[wcount-1+1];
+            gt = new double[wcount-1+1];
+            rx = new double[ntotal+nout-1+1, wcount-1+1];
+            ry = new double[ntotal+nout-1+1, wcount-1+1];
+            rdx = new double[ntotal+nout-1+1, wcount-1+1];
+            rdy = new double[ntotal+nout-1+1, wcount-1+1];
+            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,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_];
+                }
+                if( mlpissoftmax(ref network) )
+                {
+                    
+                    //
+                    // class labels outputs
+                    //
+                    kl = (int)Math.Round(xy[k,nin]);
+                    for(i=0; i<=nout-1; i++)
+                    {
+                        if( i==kl )
+                        {
+                            desiredy[i] = 1;
+                        }
+                        else
+                        {
+                            desiredy[i] = 0;
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // real outputs
+                    //
+                    i1_ = (nin) - (0);
+                    for(i_=0; i_<=nout-1;i_++)
+                    {
+                        desiredy[i_] = xy[k,i_+i1_];
+                    }
+                }
+                if( naturalerr )
+                {
+                    mlpgradn(ref network, ref x, ref desiredy, ref et, ref gt);
+                }
+                else
+                {
+                    mlpgrad(ref network, ref x, ref desiredy, ref et, ref 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*nfieldwidth;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        rx[i,i_] = zeros[i_];
+                    }
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        ry[i,i_] = zeros[i_];
+                    }
+                    if( network.structinfo[offs+0]>0 )
+                    {
+                        
+                        //
+                        // Activation function
+                        //
+                        n1 = network.structinfo[offs+2];
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rx[i,i_] = ry[n1,i_];
+                        }
+                        v = network.dfdnet[i];
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            ry[i,i_] = v*rx[i,i_];
+                        }
+                    }
+                    if( network.structinfo[offs+0]==0 )
+                    {
+                        
+                        //
+                        // Adaptive summator
+                        //
+                        n1 = network.structinfo[offs+2];
+                        n2 = n1+network.structinfo[offs+1]-1;
+                        w1 = network.structinfo[offs+3];
+                        w2 = w1+network.structinfo[offs+1]-1;
+                        for(j=n1; j<=n2; j++)
+                        {
+                            v = network.weights[w1+j-n1];
+                            for(i_=0; i_<=wcount-1;i_++)
+                            {
+                                rx[i,i_] = rx[i,i_] + v*ry[j,i_];
+                            }
+                            rx[i,w1+j-n1] = rx[i,w1+j-n1]+network.neurons[j];
+                        }
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            ry[i,i_] = rx[i,i_];
+                        }
+                    }
+                    if( network.structinfo[offs+0]<0 )
+                    {
+                        bflag = true;
+                        if( network.structinfo[offs+0]==-2 )
+                        {
+                            
+                            //
+                            // input neuron, left unchanged
+                            //
+                            bflag = false;
+                        }
+                        if( network.structinfo[offs+0]==-3 )
+                        {
+                            
+                            //
+                            // "-1" neuron, left unchanged
+                            //
+                            bflag = false;
+                        }
+                        if( network.structinfo[offs+0]==-4 )
+                        {
+                            
+                            //
+                            // "0" neuron, left unchanged
+                            //
+                            bflag = false;
+                        }
+                        System.Diagnostics.Debug.Assert(!bflag, "MLPHessianNBatch: internal error - unknown neuron type!");
+                    }
+                }
+                
+                //
+                // 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,i_] = zeros[i_];
+                    }
+                }
+                if( network.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,i_] = ry[n1,i_];
+                        }
+                        v = network.columnsigmas[nin+i];
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            ry[n2,i_] = v*rx[n2,i_];
+                        }
+                        
+                        //
+                        // Initialization of RDY
+                        //
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rdy[n2,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.columnsigmas[nin+i];
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rdx[n2,i_] = df*rdy[n2,i_];
+                        }
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rdy[n1,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.neurons[ntotal-nout];
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            mx = Math.Max(mx, network.neurons[ntotal-nout+i]);
+                        }
+                        s = 0;
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            network.nwbuf[i] = Math.Exp(network.neurons[ntotal-nout+i]-mx);
+                            s = s+network.nwbuf[i];
+                        }
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            for(j=0; j<=nout-1; j++)
+                            {
+                                if( j==i )
+                                {
+                                    deidyj = t*network.nwbuf[i]*(s-network.nwbuf[i])/AP.Math.Sqr(s);
+                                    for(i_=0; i_<=wcount-1;i_++)
+                                    {
+                                        rdy[ntotal-nout+i,i_] = rdy[ntotal-nout+i,i_] + deidyj*ry[ntotal-nout+i,i_];
+                                    }
+                                }
+                                else
+                                {
+                                    deidyj = -(t*network.nwbuf[i]*network.nwbuf[j]/AP.Math.Sqr(s));
+                                    for(i_=0; i_<=wcount-1;i_++)
+                                    {
+                                        rdy[ntotal-nout+i,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.neurons[ntotal-nout];
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            mx = Math.Max(mx, network.neurons[ntotal-nout+i]);
+                        }
+                        s = 0;
+                        s2 = 0;
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            network.nwbuf[i] = Math.Exp(network.neurons[ntotal-nout+i]-mx);
+                            s = s+network.nwbuf[i];
+                            s2 = s2+AP.Math.Sqr(network.nwbuf[i]);
+                        }
+                        q = 0;
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            q = q+(network.y[i]-desiredy[i])*network.nwbuf[i];
+                        }
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            z = -q+(network.y[i]-desiredy[i])*s;
+                            expi = network.nwbuf[i];
+                            for(j=0; j<=nout-1; j++)
+                            {
+                                expj = network.nwbuf[j];
+                                if( j==i )
+                                {
+                                    deidyj = expi/AP.Math.Sqr(s)*((z+expi)*(s-2*expi)/s+expi*s2/AP.Math.Sqr(s));
+                                }
+                                else
+                                {
+                                    deidyj = expi*expj/AP.Math.Sqr(s)*(s2/AP.Math.Sqr(s)-2*z/s-(expi+expj)/s+(network.y[i]-desiredy[i])-(network.y[j]-desiredy[j]));
+                                }
+                                for(i_=0; i_<=wcount-1;i_++)
+                                {
+                                    rdy[ntotal-nout+i,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*nfieldwidth;
+                    if( network.structinfo[offs+0]>0 )
+                    {
+                        n1 = network.structinfo[offs+2];
+                        
+                        //
+                        // First, calculate R(dE/dX).
+                        //
+                        mlpactivationfunction(network.neurons[n1], network.structinfo[offs+0], ref f, ref df, ref d2f);
+                        v = d2f*network.derror[i];
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rdx[i,i_] = df*rdy[i,i_];
+                        }
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rdx[i,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,i_] = rdy[n1,i_] + rdx[i,i_];
+                        }
+                    }
+                    if( network.structinfo[offs+0]==0 )
+                    {
+                        
+                        //
+                        // Adaptive summator
+                        //
+                        n1 = network.structinfo[offs+2];
+                        n2 = n1+network.structinfo[offs+1]-1;
+                        w1 = network.structinfo[offs+3];
+                        w2 = w1+network.structinfo[offs+1]-1;
+                        
+                        //
+                        // First, calculate R(dE/dX).
+                        //
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            rdx[i,i_] = rdy[i,i_];
+                        }
+                        
+                        //
+                        // Then, calculate R(dE/dWij)
+                        //
+                        for(j=w1; j<=w2; j++)
+                        {
+                            v = network.neurons[n1+j-w1];
+                            for(i_=0; i_<=wcount-1;i_++)
+                            {
+                                h[j,i_] = h[j,i_] + v*rdx[i,i_];
+                            }
+                            v = network.derror[i];
+                            for(i_=0; i_<=wcount-1;i_++)
+                            {
+                                h[j,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.weights[j];
+                            for(i_=0; i_<=wcount-1;i_++)
+                            {
+                                rdy[n1+j-w1,i_] = rdy[n1+j-w1,i_] + v*rdx[i,i_];
+                            }
+                            rdy[n1+j-w1,j] = rdy[n1+j-w1,j]+network.derror[i];
+                        }
+                    }
+                    if( network.structinfo[offs+0]<0 )
+                    {
+                        bflag = false;
+                        if( network.structinfo[offs+0]==-2 | network.structinfo[offs+0]==-3 | network.structinfo[offs+0]==-4 )
+                        {
+                            
+                            //
+                            // Special neuron type, no back-propagation required
+                            //
+                            bflag = true;
+                        }
+                        System.Diagnostics.Debug.Assert(bflag, "MLPHessianNBatch: unknown neuron type!");
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine
+
+        Network must be processed by MLPProcess on X
+        *************************************************************************/
+        private static void mlpinternalcalculategradient(ref multilayerperceptron network,
+            ref double[] neurons,
+            ref double[] weights,
+            ref double[] derror,
+            ref double[] grad,
+            bool naturalerrorfunc)
+        {
+            int i = 0;
+            int j = 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 = new bool();
+            int i_ = 0;
+            int i1_ = 0;
+
+            
+            //
+            // Read network geometry
+            //
+            nin = network.structinfo[1];
+            nout = network.structinfo[2];
+            ntotal = network.structinfo[3];
+            istart = network.structinfo[5];
+            
+            //
+            // Pre-processing of dError/dOut:
+            // from dError/dOut(normalized) to dError/dOut(non-normalized)
+            //
+            System.Diagnostics.Debug.Assert(network.structinfo[6]==0 | network.structinfo[6]==1, "MLPInternalCalculateGradient: unknown normalization type!");
+            if( network.structinfo[6]==1 )
+            {
+                
+                //
+                // Softmax
+                //
+                if( !naturalerrorfunc )
+                {
+                    mx = network.neurons[ntotal-nout];
+                    for(i=0; i<=nout-1; i++)
+                    {
+                        mx = Math.Max(mx, network.neurons[ntotal-nout+i]);
+                    }
+                    net = 0;
+                    for(i=0; i<=nout-1; i++)
+                    {
+                        network.nwbuf[i] = Math.Exp(network.neurons[ntotal-nout+i]-mx);
+                        net = net+network.nwbuf[i];
+                    }
+                    i1_ = (0)-(ntotal-nout);
+                    v = 0.0;
+                    for(i_=ntotal-nout; i_<=ntotal-1;i_++)
+                    {
+                        v += network.derror[i_]*network.nwbuf[i_+i1_];
+                    }
+                    for(i=0; i<=nout-1; i++)
+                    {
+                        fown = network.nwbuf[i];
+                        deown = network.derror[ntotal-nout+i];
+                        network.nwbuf[nout+i] = (-v+deown*fown+deown*(net-fown))*fown/AP.Math.Sqr(net);
+                    }
+                    for(i=0; i<=nout-1; i++)
+                    {
+                        network.derror[ntotal-nout+i] = network.nwbuf[nout+i];
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Un-standardisation
+                //
+                for(i=0; i<=nout-1; i++)
+                {
+                    network.derror[ntotal-nout+i] = network.derror[ntotal-nout+i]*network.columnsigmas[nin+i];
+                }
+            }
+            
+            //
+            // Backpropagation
+            //
+            for(i=ntotal-1; i>=0; i--)
+            {
+                
+                //
+                // Extract info
+                //
+                offs = istart+i*nfieldwidth;
+                if( network.structinfo[offs+0]>0 )
+                {
+                    
+                    //
+                    // Activation function
+                    //
+                    dedf = network.derror[i];
+                    dfdnet = network.dfdnet[i];
+                    derror[network.structinfo[offs+2]] = derror[network.structinfo[offs+2]]+dedf*dfdnet;
+                }
+                if( network.structinfo[offs+0]==0 )
+                {
+                    
+                    //
+                    // Adaptive summator
+                    //
+                    n1 = network.structinfo[offs+2];
+                    n2 = n1+network.structinfo[offs+1]-1;
+                    w1 = network.structinfo[offs+3];
+                    w2 = w1+network.structinfo[offs+1]-1;
+                    dedf = network.derror[i];
+                    dfdnet = 1.0;
+                    v = dedf*dfdnet;
+                    i1_ = (n1) - (w1);
+                    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_];
+                    }
+                }
+                if( network.structinfo[offs+0]<0 )
+                {
+                    bflag = false;
+                    if( network.structinfo[offs+0]==-2 | network.structinfo[offs+0]==-3 | network.structinfo[offs+0]==-4 )
+                    {
+                        
+                        //
+                        // Special neuron type, no back-propagation required
+                        //
+                        bflag = true;
+                    }
+                    System.Diagnostics.Debug.Assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!");
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine, chunked gradient
+        *************************************************************************/
+        private static void mlpchunkedgradient(ref multilayerperceptron network,
+            ref double[,] xy,
+            int cstart,
+            int csize,
+            ref double e,
+            ref double[] grad,
+            bool naturalerrorfunc)
+        {
+            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 dedf = 0;
+            double dfdnet = 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 = new bool();
+            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.structinfo[1];
+            nout = network.structinfo[2];
+            ntotal = network.structinfo[3];
+            istart = network.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.chunks[izeros,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++)
+                {
+                    if( (double)(network.columnsigmas[i])!=(double)(0) )
+                    {
+                        network.chunks[i,j] = (xy[c1+j,i]-network.columnmeans[i])/network.columnsigmas[i];
+                    }
+                    else
+                    {
+                        network.chunks[i,j] = xy[c1+j,i]-network.columnmeans[i];
+                    }
+                }
+            }
+            for(i=0; i<=ntotal-1; i++)
+            {
+                offs = istart+i*nfieldwidth;
+                if( network.structinfo[offs+0]>0 )
+                {
+                    
+                    //
+                    // Activation function:
+                    // * calculate F vector, F(i) = F(NET(i))
+                    //
+                    n1 = network.structinfo[offs+2];
+                    for(i_=0; i_<=csize-1;i_++)
+                    {
+                        network.chunks[i,i_] = network.chunks[n1,i_];
+                    }
+                    for(j=0; j<=csize-1; j++)
+                    {
+                        mlpactivationfunction(network.chunks[i,j], network.structinfo[offs+0], ref f, ref df, ref d2f);
+                        network.chunks[i,j] = f;
+                        network.chunks[idfdnet+i,j] = df;
+                    }
+                }
+                if( network.structinfo[offs+0]==0 )
+                {
+                    
+                    //
+                    // Adaptive summator:
+                    // * calculate NET vector, NET(i) = SUM(W(j,i)*Neurons(j),j=N1..N2)
+                    //
+                    n1 = network.structinfo[offs+2];
+                    n2 = n1+network.structinfo[offs+1]-1;
+                    w1 = network.structinfo[offs+3];
+                    w2 = w1+network.structinfo[offs+1]-1;
+                    for(i_=0; i_<=csize-1;i_++)
+                    {
+                        network.chunks[i,i_] = network.chunks[izeros,i_];
+                    }
+                    for(j=n1; j<=n2; j++)
+                    {
+                        v = network.weights[w1+j-n1];
+                        for(i_=0; i_<=csize-1;i_++)
+                        {
+                            network.chunks[i,i_] = network.chunks[i,i_] + v*network.chunks[j,i_];
+                        }
+                    }
+                }
+                if( network.structinfo[offs+0]<0 )
+                {
+                    bflag = false;
+                    if( network.structinfo[offs+0]==-2 )
+                    {
+                        
+                        //
+                        // input neuron, left unchanged
+                        //
+                        bflag = true;
+                    }
+                    if( network.structinfo[offs+0]==-3 )
+                    {
+                        
+                        //
+                        // "-1" neuron
+                        //
+                        for(k=0; k<=csize-1; k++)
+                        {
+                            network.chunks[i,k] = -1;
+                        }
+                        bflag = true;
+                    }
+                    if( network.structinfo[offs+0]==-4 )
+                    {
+                        
+                        //
+                        // "0" neuron
+                        //
+                        for(k=0; k<=csize-1; k++)
+                        {
+                            network.chunks[i,k] = 0;
+                        }
+                        bflag = true;
+                    }
+                    System.Diagnostics.Debug.Assert(bflag, "MLPChunkedGradient: internal error - unknown neuron type!");
+                }
+            }
+            
+            //
+            // Post-processing, error, dError/dOut
+            //
+            for(i=0; i<=ntotal-1; i++)
+            {
+                for(i_=0; i_<=csize-1;i_++)
+                {
+                    network.chunks[iderror+i,i_] = network.chunks[izeros,i_];
+                }
+            }
+            System.Diagnostics.Debug.Assert(network.structinfo[6]==0 | network.structinfo[6]==1, "MLPChunkedGradient: unknown normalization type!");
+            if( network.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.chunks[ntotal-nout,k];
+                    for(i=1; i<=nout-1; i++)
+                    {
+                        mx = Math.Max(mx, network.chunks[ntotal-nout+i,k]);
+                    }
+                    net = 0;
+                    for(i=0; i<=nout-1; i++)
+                    {
+                        network.nwbuf[i] = Math.Exp(network.chunks[ntotal-nout+i,k]-mx);
+                        net = net+network.nwbuf[i];
+                    }
+                    
+                    //
+                    // Calculate error function and dError/dOut
+                    //
+                    if( naturalerrorfunc )
+                    {
+                        
+                        //
+                        // Natural error func.
+                        //
+                        //
+                        s = 1;
+                        lnnet = Math.Log(net);
+                        kl = (int)Math.Round(xy[cstart+k,nin]);
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            if( i==kl )
+                            {
+                                v = 1;
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            network.chunks[iderror+ntotal-nout+i,k] = s*network.nwbuf[i]/net-v;
+                            e = e+safecrossentropy(v, network.nwbuf[i]/net);
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Least squares error func
+                        // Error, dError/dOut(normalized)
+                        //
+                        kl = (int)Math.Round(xy[cstart+k,nin]);
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            if( i==kl )
+                            {
+                                v = network.nwbuf[i]/net-1;
+                            }
+                            else
+                            {
+                                v = network.nwbuf[i]/net;
+                            }
+                            network.nwbuf[nout+i] = v;
+                            e = e+AP.Math.Sqr(v)/2;
+                        }
+                        
+                        //
+                        // From dError/dOut(normalized) to dError/dOut(non-normalized)
+                        //
+                        i1_ = (0)-(nout);
+                        v = 0.0;
+                        for(i_=nout; i_<=2*nout-1;i_++)
+                        {
+                            v += network.nwbuf[i_]*network.nwbuf[i_+i1_];
+                        }
+                        for(i=0; i<=nout-1; i++)
+                        {
+                            fown = network.nwbuf[i];
+                            deown = network.nwbuf[nout+i];
+                            network.chunks[iderror+ntotal-nout+i,k] = (-v+deown*fown+deown*(net-fown))*fown/AP.Math.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.chunks[ntotal-nout+i,j]*network.columnsigmas[nin+i]+network.columnmeans[nin+i]-xy[cstart+j,nin+i];
+                        network.chunks[iderror+ntotal-nout+i,j] = v*network.columnsigmas[nin+i];
+                        e = e+AP.Math.Sqr(v)/2;
+                    }
+                }
+            }
+            
+            //
+            // Backpropagation
+            //
+            for(i=ntotal-1; i>=0; i--)
+            {
+                
+                //
+                // Extract info
+                //
+                offs = istart+i*nfieldwidth;
+                if( network.structinfo[offs+0]>0 )
+                {
+                    
+                    //
+                    // Activation function
+                    //
+                    n1 = network.structinfo[offs+2];
+                    for(k=0; k<=csize-1; k++)
+                    {
+                        network.chunks[iderror+i,k] = network.chunks[iderror+i,k]*network.chunks[idfdnet+i,k];
+                    }
+                    for(i_=0; i_<=csize-1;i_++)
+                    {
+                        network.chunks[iderror+n1,i_] = network.chunks[iderror+n1,i_] + network.chunks[iderror+i,i_];
+                    }
+                }
+                if( network.structinfo[offs+0]==0 )
+                {
+                    
+                    //
+                    // "Normal" activation function
+                    //
+                    n1 = network.structinfo[offs+2];
+                    n2 = n1+network.structinfo[offs+1]-1;
+                    w1 = network.structinfo[offs+3];
+                    w2 = w1+network.structinfo[offs+1]-1;
+                    for(j=w1; j<=w2; j++)
+                    {
+                        v = 0.0;
+                        for(i_=0; i_<=csize-1;i_++)
+                        {
+                            v += network.chunks[n1+j-w1,i_]*network.chunks[iderror+i,i_];
+                        }
+                        grad[j] = grad[j]+v;
+                    }
+                    for(j=n1; j<=n2; j++)
+                    {
+                        v = network.weights[w1+j-n1];
+                        for(i_=0; i_<=csize-1;i_++)
+                        {
+                            network.chunks[iderror+j,i_] = network.chunks[iderror+j,i_] + v*network.chunks[iderror+i,i_];
+                        }
+                    }
+                }
+                if( network.structinfo[offs+0]<0 )
+                {
+                    bflag = false;
+                    if( network.structinfo[offs+0]==-2 | network.structinfo[offs+0]==-3 | network.structinfo[offs+0]==-4 )
+                    {
+                        
+                        //
+                        // Special neuron type, no back-propagation required
+                        //
+                        bflag = true;
+                    }
+                    System.Diagnostics.Debug.Assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!");
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Returns T*Ln(T/Z), guarded against overflow/underflow.
+        Internal subroutine.
+        *************************************************************************/
+        private static double safecrossentropy(double t,
+            double z)
+        {
+            double result = 0;
+            double r = 0;
+
+            if( (double)(t)==(double)(0) )
+            {
+                result = 0;
+            }
+            else
+            {
+                if( (double)(Math.Abs(z))>(double)(1) )
+                {
+                    
+                    //
+                    // Shouldn't be the case with softmax,
+                    // but we just want to be sure.
+                    //
+                    if( (double)(t/z)==(double)(0) )
+                    {
+                        r = AP.Math.MinRealNumber;
+                    }
+                    else
+                    {
+                        r = t/z;
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // Normal case
+                    //
+                    if( (double)(z)==(double)(0) | (double)(Math.Abs(t))>=(double)(AP.Math.MaxRealNumber*Math.Abs(z)) )
+                    {
+                        r = AP.Math.MaxRealNumber;
+                    }
+                    else
+                    {
+                        r = t/z;
+                    }
+                }
+                result = t*Math.Log(r);
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlpe.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlpe.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlpe.cs	(revision 2645)
@@ -0,0 +1,1512 @@
+/*************************************************************************
+Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class mlpe
+    {
+        /*************************************************************************
+        Neural networks ensemble
+        *************************************************************************/
+        public struct mlpensemble
+        {
+            public int[] structinfo;
+            public int ensemblesize;
+            public int nin;
+            public int nout;
+            public int wcount;
+            public bool issoftmax;
+            public bool postprocessing;
+            public double[] weights;
+            public double[] columnmeans;
+            public double[] columnsigmas;
+            public int serializedlen;
+            public double[] serializedmlp;
+            public double[] tmpweights;
+            public double[] tmpmeans;
+            public double[] tmpsigmas;
+            public double[] neurons;
+            public double[] dfdnet;
+            public double[] y;
+        };
+
+
+
+
+        public const int mlpntotaloffset = 3;
+        public const int mlpevnum = 9;
+
+
+        /*************************************************************************
+        Like MLPCreate0, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreate0(int nin,
+            int nout,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreate0(nin, nout, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreate1, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreate1(int nin,
+            int nhid,
+            int nout,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreate1(nin, nhid, nout, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreate2, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreate2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreate2(nin, nhid1, nhid2, nout, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateB0, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreateb0(int nin,
+            int nout,
+            double b,
+            double d,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreateb0(nin, nout, b, d, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateB1, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreateb1(int nin,
+            int nhid,
+            int nout,
+            double b,
+            double d,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreateb1(nin, nhid, nout, b, d, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateB2, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreateb2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            double b,
+            double d,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreateb2(nin, nhid1, nhid2, nout, b, d, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateR0, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreater0(int nin,
+            int nout,
+            double a,
+            double b,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreater0(nin, nout, a, b, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateR1, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreater1(int nin,
+            int nhid,
+            int nout,
+            double a,
+            double b,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreater1(nin, nhid, nout, a, b, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateR2, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreater2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            double a,
+            double b,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreater2(nin, nhid1, nhid2, nout, a, b, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateC0, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreatec0(int nin,
+            int nout,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreatec0(nin, nout, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateC1, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreatec1(int nin,
+            int nhid,
+            int nout,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreatec1(nin, nhid, nout, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Like MLPCreateC2, but for ensembles.
+
+          -- ALGLIB --
+             Copyright 18.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreatec2(int nin,
+            int nhid1,
+            int nhid2,
+            int nout,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            mlpbase.multilayerperceptron net = new mlpbase.multilayerperceptron();
+
+            mlpbase.mlpcreatec2(nin, nhid1, nhid2, nout, ref net);
+            mlpecreatefromnetwork(ref net, ensemblesize, ref ensemble);
+        }
+
+
+        /*************************************************************************
+        Creates ensemble from network. Only network geometry is copied.
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecreatefromnetwork(ref mlpbase.multilayerperceptron network,
+            int ensemblesize,
+            ref mlpensemble ensemble)
+        {
+            int i = 0;
+            int ccount = 0;
+            int rlen = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(ensemblesize>0, "MLPECreate: incorrect ensemble size!");
+            
+            //
+            // network properties
+            //
+            mlpbase.mlpproperties(ref network, ref ensemble.nin, ref ensemble.nout, ref ensemble.wcount);
+            if( mlpbase.mlpissoftmax(ref network) )
+            {
+                ccount = ensemble.nin;
+            }
+            else
+            {
+                ccount = ensemble.nin+ensemble.nout;
+            }
+            ensemble.postprocessing = false;
+            ensemble.issoftmax = mlpbase.mlpissoftmax(ref network);
+            ensemble.ensemblesize = ensemblesize;
+            
+            //
+            // structure information
+            //
+            ensemble.structinfo = new int[network.structinfo[0]-1+1];
+            for(i=0; i<=network.structinfo[0]-1; i++)
+            {
+                ensemble.structinfo[i] = network.structinfo[i];
+            }
+            
+            //
+            // weights, means, sigmas
+            //
+            ensemble.weights = new double[ensemblesize*ensemble.wcount-1+1];
+            ensemble.columnmeans = new double[ensemblesize*ccount-1+1];
+            ensemble.columnsigmas = new double[ensemblesize*ccount-1+1];
+            for(i=0; i<=ensemblesize*ensemble.wcount-1; i++)
+            {
+                ensemble.weights[i] = AP.Math.RandomReal()-0.5;
+            }
+            for(i=0; i<=ensemblesize-1; i++)
+            {
+                i1_ = (0) - (i*ccount);
+                for(i_=i*ccount; i_<=(i+1)*ccount-1;i_++)
+                {
+                    ensemble.columnmeans[i_] = network.columnmeans[i_+i1_];
+                }
+                i1_ = (0) - (i*ccount);
+                for(i_=i*ccount; i_<=(i+1)*ccount-1;i_++)
+                {
+                    ensemble.columnsigmas[i_] = network.columnsigmas[i_+i1_];
+                }
+            }
+            
+            //
+            // serialized part
+            //
+            mlpbase.mlpserialize(ref network, ref ensemble.serializedmlp, ref ensemble.serializedlen);
+            
+            //
+            // temporaries, internal buffers
+            //
+            ensemble.tmpweights = new double[ensemble.wcount-1+1];
+            ensemble.tmpmeans = new double[ccount-1+1];
+            ensemble.tmpsigmas = new double[ccount-1+1];
+            ensemble.neurons = new double[ensemble.structinfo[mlpntotaloffset]-1+1];
+            ensemble.dfdnet = new double[ensemble.structinfo[mlpntotaloffset]-1+1];
+            ensemble.y = new double[ensemble.nout-1+1];
+        }
+
+
+        /*************************************************************************
+        Copying of MLPEnsemble strucure
+
+        INPUT PARAMETERS:
+            Ensemble1 -   original
+
+        OUTPUT PARAMETERS:
+            Ensemble2 -   copy
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpecopy(ref mlpensemble ensemble1,
+            ref mlpensemble ensemble2)
+        {
+            int i = 0;
+            int ssize = 0;
+            int ccount = 0;
+            int ntotal = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            int i_ = 0;
+
+            
+            //
+            // Unload info
+            //
+            ssize = ensemble1.structinfo[0];
+            if( ensemble1.issoftmax )
+            {
+                ccount = ensemble1.nin;
+            }
+            else
+            {
+                ccount = ensemble1.nin+ensemble1.nout;
+            }
+            ntotal = ensemble1.structinfo[mlpntotaloffset];
+            
+            //
+            // Allocate space
+            //
+            ensemble2.structinfo = new int[ssize-1+1];
+            ensemble2.weights = new double[ensemble1.ensemblesize*ensemble1.wcount-1+1];
+            ensemble2.columnmeans = new double[ensemble1.ensemblesize*ccount-1+1];
+            ensemble2.columnsigmas = new double[ensemble1.ensemblesize*ccount-1+1];
+            ensemble2.tmpweights = new double[ensemble1.wcount-1+1];
+            ensemble2.tmpmeans = new double[ccount-1+1];
+            ensemble2.tmpsigmas = new double[ccount-1+1];
+            ensemble2.serializedmlp = new double[ensemble1.serializedlen-1+1];
+            ensemble2.neurons = new double[ntotal-1+1];
+            ensemble2.dfdnet = new double[ntotal-1+1];
+            ensemble2.y = new double[ensemble1.nout-1+1];
+            
+            //
+            // Copy
+            //
+            ensemble2.nin = ensemble1.nin;
+            ensemble2.nout = ensemble1.nout;
+            ensemble2.wcount = ensemble1.wcount;
+            ensemble2.ensemblesize = ensemble1.ensemblesize;
+            ensemble2.issoftmax = ensemble1.issoftmax;
+            ensemble2.postprocessing = ensemble1.postprocessing;
+            ensemble2.serializedlen = ensemble1.serializedlen;
+            for(i=0; i<=ssize-1; i++)
+            {
+                ensemble2.structinfo[i] = ensemble1.structinfo[i];
+            }
+            for(i_=0; i_<=ensemble1.ensemblesize*ensemble1.wcount-1;i_++)
+            {
+                ensemble2.weights[i_] = ensemble1.weights[i_];
+            }
+            for(i_=0; i_<=ensemble1.ensemblesize*ccount-1;i_++)
+            {
+                ensemble2.columnmeans[i_] = ensemble1.columnmeans[i_];
+            }
+            for(i_=0; i_<=ensemble1.ensemblesize*ccount-1;i_++)
+            {
+                ensemble2.columnsigmas[i_] = ensemble1.columnsigmas[i_];
+            }
+            for(i_=0; i_<=ensemble1.serializedlen-1;i_++)
+            {
+                ensemble2.serializedmlp[i_] = ensemble1.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
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpeserialize(ref mlpensemble ensemble,
+            ref double[] ra,
+            ref int rlen)
+        {
+            int i = 0;
+            int ssize = 0;
+            int ntotal = 0;
+            int ccount = 0;
+            int hsize = 0;
+            int offs = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            hsize = 13;
+            ssize = ensemble.structinfo[0];
+            if( ensemble.issoftmax )
+            {
+                ccount = ensemble.nin;
+            }
+            else
+            {
+                ccount = ensemble.nin+ensemble.nout;
+            }
+            ntotal = ensemble.structinfo[mlpntotaloffset];
+            rlen = hsize+ssize+ensemble.ensemblesize*ensemble.wcount+2*ccount*ensemble.ensemblesize+ensemble.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
+            //
+            ra = new double[rlen-1+1];
+            ra[0] = rlen;
+            ra[1] = mlpevnum;
+            ra[2] = ensemble.ensemblesize;
+            ra[3] = ensemble.nin;
+            ra[4] = ensemble.nout;
+            ra[5] = ensemble.wcount;
+            if( ensemble.issoftmax )
+            {
+                ra[6] = 1;
+            }
+            else
+            {
+                ra[6] = 0;
+            }
+            if( ensemble.postprocessing )
+            {
+                ra[7] = 1;
+            }
+            else
+            {
+                ra[7] = 9;
+            }
+            ra[8] = ssize;
+            ra[9] = ntotal;
+            ra[10] = ccount;
+            ra[11] = hsize;
+            ra[12] = ensemble.serializedlen;
+            offs = hsize;
+            for(i=offs; i<=offs+ssize-1; i++)
+            {
+                ra[i] = ensemble.structinfo[i-offs];
+            }
+            offs = offs+ssize;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+ensemble.ensemblesize*ensemble.wcount-1;i_++)
+            {
+                ra[i_] = ensemble.weights[i_+i1_];
+            }
+            offs = offs+ensemble.ensemblesize*ensemble.wcount;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+ensemble.ensemblesize*ccount-1;i_++)
+            {
+                ra[i_] = ensemble.columnmeans[i_+i1_];
+            }
+            offs = offs+ensemble.ensemblesize*ccount;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+ensemble.ensemblesize*ccount-1;i_++)
+            {
+                ra[i_] = ensemble.columnsigmas[i_+i1_];
+            }
+            offs = offs+ensemble.ensemblesize*ccount;
+            i1_ = (0) - (offs);
+            for(i_=offs; i_<=offs+ensemble.serializedlen-1;i_++)
+            {
+                ra[i_] = ensemble.serializedmlp[i_+i1_];
+            }
+            offs = offs+ensemble.serializedlen;
+        }
+
+
+        /*************************************************************************
+        Unserialization of MLPEnsemble strucure
+
+        INPUT PARAMETERS:
+            RA      -   real array which stores ensemble
+
+        OUTPUT PARAMETERS:
+            Ensemble-   restored structure
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpeunserialize(ref double[] ra,
+            ref mlpensemble ensemble)
+        {
+            int i = 0;
+            int ssize = 0;
+            int ntotal = 0;
+            int ccount = 0;
+            int hsize = 0;
+            int offs = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[1])==mlpevnum, "MLPEUnserialize: incorrect array!");
+            
+            //
+            // load info
+            //
+            hsize = 13;
+            ensemble.ensemblesize = (int)Math.Round(ra[2]);
+            ensemble.nin = (int)Math.Round(ra[3]);
+            ensemble.nout = (int)Math.Round(ra[4]);
+            ensemble.wcount = (int)Math.Round(ra[5]);
+            ensemble.issoftmax = (int)Math.Round(ra[6])==1;
+            ensemble.postprocessing = (int)Math.Round(ra[7])==1;
+            ssize = (int)Math.Round(ra[8]);
+            ntotal = (int)Math.Round(ra[9]);
+            ccount = (int)Math.Round(ra[10]);
+            offs = (int)Math.Round(ra[11]);
+            ensemble.serializedlen = (int)Math.Round(ra[12]);
+            
+            //
+            //  Allocate arrays
+            //
+            ensemble.structinfo = new int[ssize-1+1];
+            ensemble.weights = new double[ensemble.ensemblesize*ensemble.wcount-1+1];
+            ensemble.columnmeans = new double[ensemble.ensemblesize*ccount-1+1];
+            ensemble.columnsigmas = new double[ensemble.ensemblesize*ccount-1+1];
+            ensemble.tmpweights = new double[ensemble.wcount-1+1];
+            ensemble.tmpmeans = new double[ccount-1+1];
+            ensemble.tmpsigmas = new double[ccount-1+1];
+            ensemble.neurons = new double[ntotal-1+1];
+            ensemble.dfdnet = new double[ntotal-1+1];
+            ensemble.serializedmlp = new double[ensemble.serializedlen-1+1];
+            ensemble.y = new double[ensemble.nout-1+1];
+            
+            //
+            // load data
+            //
+            for(i=offs; i<=offs+ssize-1; i++)
+            {
+                ensemble.structinfo[i-offs] = (int)Math.Round(ra[i]);
+            }
+            offs = offs+ssize;
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=ensemble.ensemblesize*ensemble.wcount-1;i_++)
+            {
+                ensemble.weights[i_] = ra[i_+i1_];
+            }
+            offs = offs+ensemble.ensemblesize*ensemble.wcount;
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=ensemble.ensemblesize*ccount-1;i_++)
+            {
+                ensemble.columnmeans[i_] = ra[i_+i1_];
+            }
+            offs = offs+ensemble.ensemblesize*ccount;
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=ensemble.ensemblesize*ccount-1;i_++)
+            {
+                ensemble.columnsigmas[i_] = ra[i_+i1_];
+            }
+            offs = offs+ensemble.ensemblesize*ccount;
+            i1_ = (offs) - (0);
+            for(i_=0; i_<=ensemble.serializedlen-1;i_++)
+            {
+                ensemble.serializedmlp[i_] = ra[i_+i1_];
+            }
+            offs = offs+ensemble.serializedlen;
+        }
+
+
+        /*************************************************************************
+        Randomization of MLP ensemble
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlperandomize(ref mlpensemble ensemble)
+        {
+            int i = 0;
+
+            for(i=0; i<=ensemble.ensemblesize*ensemble.wcount-1; i++)
+            {
+                ensemble.weights[i] = AP.Math.RandomReal()-0.5;
+            }
+        }
+
+
+        /*************************************************************************
+        Return ensemble properties (number of inputs and outputs).
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpeproperties(ref mlpensemble ensemble,
+            ref int nin,
+            ref int nout)
+        {
+            nin = ensemble.nin;
+            nout = ensemble.nout;
+        }
+
+
+        /*************************************************************************
+        Return normalization type (whether ensemble is SOFTMAX-normalized or not).
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool mlpeissoftmax(ref mlpensemble ensemble)
+        {
+            bool result = new bool();
+
+            result = ensemble.issoftmax;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Procesing
+
+        INPUT PARAMETERS:
+            Ensemble-   neural networks ensemble
+            X       -   input vector,  array[0..NIn-1].
+
+        OUTPUT PARAMETERS:
+            Y       -   result. Regression estimate when solving regression  task,
+                        vector of posterior probabilities for classification task.
+                        Subroutine does not allocate memory for this vector, it is
+                        responsibility of a caller to allocate it. Array  must  be
+                        at least [0..NOut-1].
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpeprocess(ref mlpensemble ensemble,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            int es = 0;
+            int wc = 0;
+            int cc = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            es = ensemble.ensemblesize;
+            wc = ensemble.wcount;
+            if( ensemble.issoftmax )
+            {
+                cc = ensemble.nin;
+            }
+            else
+            {
+                cc = ensemble.nin+ensemble.nout;
+            }
+            v = (double)(1)/(double)(es);
+            for(i=0; i<=ensemble.nout-1; i++)
+            {
+                y[i] = 0;
+            }
+            for(i=0; i<=es-1; i++)
+            {
+                i1_ = (i*wc) - (0);
+                for(i_=0; i_<=wc-1;i_++)
+                {
+                    ensemble.tmpweights[i_] = ensemble.weights[i_+i1_];
+                }
+                i1_ = (i*cc) - (0);
+                for(i_=0; i_<=cc-1;i_++)
+                {
+                    ensemble.tmpmeans[i_] = ensemble.columnmeans[i_+i1_];
+                }
+                i1_ = (i*cc) - (0);
+                for(i_=0; i_<=cc-1;i_++)
+                {
+                    ensemble.tmpsigmas[i_] = ensemble.columnsigmas[i_+i1_];
+                }
+                mlpbase.mlpinternalprocessvector(ref ensemble.structinfo, ref ensemble.tmpweights, ref ensemble.tmpmeans, ref ensemble.tmpsigmas, ref ensemble.neurons, ref ensemble.dfdnet, ref x, ref ensemble.y);
+                for(i_=0; i_<=ensemble.nout-1;i_++)
+                {
+                    y[i_] = y[i_] + v*ensemble.y[i_];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Relative classification error on the test set
+
+        INPUT PARAMETERS:
+            Ensemble-   ensemble
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            percent of incorrectly classified cases.
+            Works both for classifier betwork and for regression networks which
+        are used as classifiers.
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlperelclserror(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            mlpeallerrors(ref ensemble, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = relcls;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average cross-entropy (in bits per element) on the test set
+
+        INPUT PARAMETERS:
+            Ensemble-   ensemble
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            CrossEntropy/(NPoints*LN(2)).
+            Zero if ensemble solves regression task.
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpeavgce(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            mlpeallerrors(ref ensemble, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = avgce;
+            return result;
+        }
+
+
+        /*************************************************************************
+        RMS error on the test set
+
+        INPUT PARAMETERS:
+            Ensemble-   ensemble
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            root mean square error.
+            Its meaning for regression task is obvious. As for classification task
+        RMS error means error when estimating posterior probabilities.
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpermserror(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            mlpeallerrors(ref ensemble, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = rms;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average error on the test set
+
+        INPUT PARAMETERS:
+            Ensemble-   ensemble
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            Its meaning for regression task is obvious. As for classification task
+        it means average error when estimating posterior probabilities.
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpeavgerror(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            mlpeallerrors(ref ensemble, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = avg;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Average relative error on the test set
+
+        INPUT PARAMETERS:
+            Ensemble-   ensemble
+            XY      -   test set
+            NPoints -   test set size
+
+        RESULT:
+            Its meaning for regression task is obvious. As for classification task
+        it means average relative error when estimating posterior probabilities.
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double mlpeavgrelerror(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints)
+        {
+            double result = 0;
+            double relcls = 0;
+            double avgce = 0;
+            double rms = 0;
+            double avg = 0;
+            double avgrel = 0;
+
+            mlpeallerrors(ref ensemble, ref xy, npoints, ref relcls, ref avgce, ref rms, ref avg, ref avgrel);
+            result = avgrel;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Training neural networks ensemble using  bootstrap  aggregating (bagging).
+        Modified Levenberg-Marquardt algorithm is used as base training method.
+
+        INPUT PARAMETERS:
+            Ensemble    -   model with initialized geometry
+            XY          -   training set
+            NPoints     -   training set size
+            Decay       -   weight decay coefficient, >=0.001
+            Restarts    -   restarts, >0.
+
+        OUTPUT PARAMETERS:
+            Ensemble    -   trained model
+            Info        -   return code:
+                            * -2, if there is a point with class number
+                                  outside of [0..NClasses-1].
+                            * -1, if incorrect parameters was passed
+                                  (NPoints<0, Restarts<1).
+                            *  2, if task has been solved.
+            Rep         -   training report.
+            OOBErrors   -   out-of-bag generalization error estimate
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpebagginglm(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            ref int info,
+            ref mlptrain.mlpreport rep,
+            ref mlptrain.mlpcvreport ooberrors)
+        {
+            mlpebagginginternal(ref ensemble, ref xy, npoints, decay, restarts, 0.0, 0, true, ref info, ref rep, ref ooberrors);
+        }
+
+
+        /*************************************************************************
+        Training neural networks ensemble using  bootstrap  aggregating (bagging).
+        L-BFGS algorithm is used as base training method.
+
+        INPUT PARAMETERS:
+            Ensemble    -   model with initialized geometry
+            XY          -   training set
+            NPoints     -   training set size
+            Decay       -   weight decay coefficient, >=0.001
+            Restarts    -   restarts, >0.
+            WStep       -   stopping criterion, same as in MLPTrainLBFGS
+            MaxIts      -   stopping criterion, same as in MLPTrainLBFGS
+
+        OUTPUT PARAMETERS:
+            Ensemble    -   trained model
+            Info        -   return code:
+                            * -8, if both WStep=0 and MaxIts=0
+                            * -2, if there is a point with class number
+                                  outside of [0..NClasses-1].
+                            * -1, if incorrect parameters was passed
+                                  (NPoints<0, Restarts<1).
+                            *  2, if task has been solved.
+            Rep         -   training report.
+            OOBErrors   -   out-of-bag generalization error estimate
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpebagginglbfgs(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            double wstep,
+            int maxits,
+            ref int info,
+            ref mlptrain.mlpreport rep,
+            ref mlptrain.mlpcvreport ooberrors)
+        {
+            mlpebagginginternal(ref ensemble, ref xy, npoints, decay, restarts, wstep, maxits, false, ref info, ref rep, ref ooberrors);
+        }
+
+
+        /*************************************************************************
+        Training neural networks ensemble using early stopping.
+
+        INPUT PARAMETERS:
+            Ensemble    -   model with initialized geometry
+            XY          -   training set
+            NPoints     -   training set size
+            Decay       -   weight decay coefficient, >=0.001
+            Restarts    -   restarts, >0.
+
+        OUTPUT PARAMETERS:
+            Ensemble    -   trained model
+            Info        -   return code:
+                            * -2, if there is a point with class number
+                                  outside of [0..NClasses-1].
+                            * -1, if incorrect parameters was passed
+                                  (NPoints<0, Restarts<1).
+                            *  6, if task has been solved.
+            Rep         -   training report.
+            OOBErrors   -   out-of-bag generalization error estimate
+
+          -- ALGLIB --
+             Copyright 10.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpetraines(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            ref int info,
+            ref mlptrain.mlpreport rep)
+        {
+            int i = 0;
+            int k = 0;
+            int ccount = 0;
+            int pcount = 0;
+            double[,] trnxy = new double[0,0];
+            double[,] valxy = new double[0,0];
+            int trnsize = 0;
+            int valsize = 0;
+            mlpbase.multilayerperceptron network = new mlpbase.multilayerperceptron();
+            int tmpinfo = 0;
+            mlptrain.mlpreport tmprep = new mlptrain.mlpreport();
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( npoints<2 | restarts<1 | (double)(decay)<(double)(0) )
+            {
+                info = -1;
+                return;
+            }
+            if( ensemble.issoftmax )
+            {
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( (int)Math.Round(xy[i,ensemble.nin])<0 | (int)Math.Round(xy[i,ensemble.nin])>=ensemble.nout )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+            }
+            info = 6;
+            
+            //
+            // allocate
+            //
+            if( ensemble.issoftmax )
+            {
+                ccount = ensemble.nin+1;
+                pcount = ensemble.nin;
+            }
+            else
+            {
+                ccount = ensemble.nin+ensemble.nout;
+                pcount = ensemble.nin+ensemble.nout;
+            }
+            trnxy = new double[npoints-1+1, ccount-1+1];
+            valxy = new double[npoints-1+1, ccount-1+1];
+            mlpbase.mlpunserialize(ref ensemble.serializedmlp, ref network);
+            rep.ngrad = 0;
+            rep.nhess = 0;
+            rep.ncholesky = 0;
+            
+            //
+            // train networks
+            //
+            for(k=0; k<=ensemble.ensemblesize-1; k++)
+            {
+                
+                //
+                // Split set
+                //
+                do
+                {
+                    trnsize = 0;
+                    valsize = 0;
+                    for(i=0; i<=npoints-1; i++)
+                    {
+                        if( (double)(AP.Math.RandomReal())<(double)(0.66) )
+                        {
+                            
+                            //
+                            // Assign sample to training set
+                            //
+                            for(i_=0; i_<=ccount-1;i_++)
+                            {
+                                trnxy[trnsize,i_] = xy[i,i_];
+                            }
+                            trnsize = trnsize+1;
+                        }
+                        else
+                        {
+                            
+                            //
+                            // Assign sample to validation set
+                            //
+                            for(i_=0; i_<=ccount-1;i_++)
+                            {
+                                valxy[valsize,i_] = xy[i,i_];
+                            }
+                            valsize = valsize+1;
+                        }
+                    }
+                }
+                while( ! (trnsize!=0 & valsize!=0) );
+                
+                //
+                // Train
+                //
+                mlptrain.mlptraines(ref network, ref trnxy, trnsize, ref valxy, valsize, decay, restarts, ref tmpinfo, ref tmprep);
+                if( tmpinfo<0 )
+                {
+                    info = tmpinfo;
+                    return;
+                }
+                
+                //
+                // save results
+                //
+                i1_ = (0) - (k*ensemble.wcount);
+                for(i_=k*ensemble.wcount; i_<=(k+1)*ensemble.wcount-1;i_++)
+                {
+                    ensemble.weights[i_] = network.weights[i_+i1_];
+                }
+                i1_ = (0) - (k*pcount);
+                for(i_=k*pcount; i_<=(k+1)*pcount-1;i_++)
+                {
+                    ensemble.columnmeans[i_] = network.columnmeans[i_+i1_];
+                }
+                i1_ = (0) - (k*pcount);
+                for(i_=k*pcount; i_<=(k+1)*pcount-1;i_++)
+                {
+                    ensemble.columnsigmas[i_] = network.columnsigmas[i_+i1_];
+                }
+                rep.ngrad = rep.ngrad+tmprep.ngrad;
+                rep.nhess = rep.nhess+tmprep.nhess;
+                rep.ncholesky = rep.ncholesky+tmprep.ncholesky;
+            }
+        }
+
+
+        /*************************************************************************
+        Calculation of all types of errors
+
+          -- ALGLIB --
+             Copyright 17.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void mlpeallerrors(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints,
+            ref double relcls,
+            ref double avgce,
+            ref double rms,
+            ref double avg,
+            ref double avgrel)
+        {
+            int i = 0;
+            double[] buf = new double[0];
+            double[] workx = new double[0];
+            double[] y = new double[0];
+            double[] dy = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            workx = new double[ensemble.nin-1+1];
+            y = new double[ensemble.nout-1+1];
+            if( ensemble.issoftmax )
+            {
+                dy = new double[0+1];
+                bdss.dserrallocate(ensemble.nout, ref buf);
+            }
+            else
+            {
+                dy = new double[ensemble.nout-1+1];
+                bdss.dserrallocate(-ensemble.nout, ref buf);
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=ensemble.nin-1;i_++)
+                {
+                    workx[i_] = xy[i,i_];
+                }
+                mlpeprocess(ref ensemble, ref workx, ref y);
+                if( ensemble.issoftmax )
+                {
+                    dy[0] = xy[i,ensemble.nin];
+                }
+                else
+                {
+                    i1_ = (ensemble.nin) - (0);
+                    for(i_=0; i_<=ensemble.nout-1;i_++)
+                    {
+                        dy[i_] = xy[i,i_+i1_];
+                    }
+                }
+                bdss.dserraccumulate(ref buf, ref y, ref dy);
+            }
+            bdss.dserrfinish(ref buf);
+            relcls = buf[0];
+            avgce = buf[1];
+            rms = buf[2];
+            avg = buf[3];
+            avgrel = buf[4];
+        }
+
+
+        /*************************************************************************
+        Internal bagging subroutine.
+
+          -- ALGLIB --
+             Copyright 19.02.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void mlpebagginginternal(ref mlpensemble ensemble,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            double wstep,
+            int maxits,
+            bool lmalgorithm,
+            ref int info,
+            ref mlptrain.mlpreport rep,
+            ref mlptrain.mlpcvreport ooberrors)
+        {
+            double[,] xys = new double[0,0];
+            bool[] s = new bool[0];
+            double[,] oobbuf = new double[0,0];
+            int[] oobcntbuf = new int[0];
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[] dy = new double[0];
+            double[] dsbuf = new double[0];
+            int nin = 0;
+            int nout = 0;
+            int ccnt = 0;
+            int pcnt = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            double v = 0;
+            mlptrain.mlpreport tmprep = new mlptrain.mlpreport();
+            mlpbase.multilayerperceptron network = new mlpbase.multilayerperceptron();
+            int i_ = 0;
+            int i1_ = 0;
+
+            
+            //
+            // Test for inputs
+            //
+            if( !lmalgorithm & (double)(wstep)==(double)(0) & maxits==0 )
+            {
+                info = -8;
+                return;
+            }
+            if( npoints<=0 | restarts<1 | (double)(wstep)<(double)(0) | maxits<0 )
+            {
+                info = -1;
+                return;
+            }
+            if( ensemble.issoftmax )
+            {
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( (int)Math.Round(xy[i,ensemble.nin])<0 | (int)Math.Round(xy[i,ensemble.nin])>=ensemble.nout )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+            }
+            
+            //
+            // allocate temporaries
+            //
+            info = 2;
+            rep.ngrad = 0;
+            rep.nhess = 0;
+            rep.ncholesky = 0;
+            ooberrors.relclserror = 0;
+            ooberrors.avgce = 0;
+            ooberrors.rmserror = 0;
+            ooberrors.avgerror = 0;
+            ooberrors.avgrelerror = 0;
+            nin = ensemble.nin;
+            nout = ensemble.nout;
+            if( ensemble.issoftmax )
+            {
+                ccnt = nin+1;
+                pcnt = nin;
+            }
+            else
+            {
+                ccnt = nin+nout;
+                pcnt = nin+nout;
+            }
+            xys = new double[npoints-1+1, ccnt-1+1];
+            s = new bool[npoints-1+1];
+            oobbuf = new double[npoints-1+1, nout-1+1];
+            oobcntbuf = new int[npoints-1+1];
+            x = new double[nin-1+1];
+            y = new double[nout-1+1];
+            if( ensemble.issoftmax )
+            {
+                dy = new double[0+1];
+            }
+            else
+            {
+                dy = new double[nout-1+1];
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(j=0; j<=nout-1; j++)
+                {
+                    oobbuf[i,j] = 0;
+                }
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                oobcntbuf[i] = 0;
+            }
+            mlpbase.mlpunserialize(ref ensemble.serializedmlp, ref network);
+            
+            //
+            // main bagging cycle
+            //
+            for(k=0; k<=ensemble.ensemblesize-1; k++)
+            {
+                
+                //
+                // prepare dataset
+                //
+                for(i=0; i<=npoints-1; i++)
+                {
+                    s[i] = false;
+                }
+                for(i=0; i<=npoints-1; i++)
+                {
+                    j = AP.Math.RandomInteger(npoints);
+                    s[j] = true;
+                    for(i_=0; i_<=ccnt-1;i_++)
+                    {
+                        xys[i,i_] = xy[j,i_];
+                    }
+                }
+                
+                //
+                // train
+                //
+                if( lmalgorithm )
+                {
+                    mlptrain.mlptrainlm(ref network, ref xys, npoints, decay, restarts, ref info, ref tmprep);
+                }
+                else
+                {
+                    mlptrain.mlptrainlbfgs(ref network, ref xys, npoints, decay, restarts, wstep, maxits, ref info, ref tmprep);
+                }
+                if( info<0 )
+                {
+                    return;
+                }
+                
+                //
+                // save results
+                //
+                rep.ngrad = rep.ngrad+tmprep.ngrad;
+                rep.nhess = rep.nhess+tmprep.nhess;
+                rep.ncholesky = rep.ncholesky+tmprep.ncholesky;
+                i1_ = (0) - (k*ensemble.wcount);
+                for(i_=k*ensemble.wcount; i_<=(k+1)*ensemble.wcount-1;i_++)
+                {
+                    ensemble.weights[i_] = network.weights[i_+i1_];
+                }
+                i1_ = (0) - (k*pcnt);
+                for(i_=k*pcnt; i_<=(k+1)*pcnt-1;i_++)
+                {
+                    ensemble.columnmeans[i_] = network.columnmeans[i_+i1_];
+                }
+                i1_ = (0) - (k*pcnt);
+                for(i_=k*pcnt; i_<=(k+1)*pcnt-1;i_++)
+                {
+                    ensemble.columnsigmas[i_] = network.columnsigmas[i_+i1_];
+                }
+                
+                //
+                // OOB estimates
+                //
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( !s[i] )
+                    {
+                        for(i_=0; i_<=nin-1;i_++)
+                        {
+                            x[i_] = xy[i,i_];
+                        }
+                        mlpbase.mlpprocess(ref network, ref x, ref y);
+                        for(i_=0; i_<=nout-1;i_++)
+                        {
+                            oobbuf[i,i_] = oobbuf[i,i_] + y[i_];
+                        }
+                        oobcntbuf[i] = oobcntbuf[i]+1;
+                    }
+                }
+            }
+            
+            //
+            // OOB estimates
+            //
+            if( ensemble.issoftmax )
+            {
+                bdss.dserrallocate(nout, ref dsbuf);
+            }
+            else
+            {
+                bdss.dserrallocate(-nout, ref dsbuf);
+            }
+            for(i=0; i<=npoints-1; i++)
+            {
+                if( oobcntbuf[i]!=0 )
+                {
+                    v = (double)(1)/(double)(oobcntbuf[i]);
+                    for(i_=0; i_<=nout-1;i_++)
+                    {
+                        y[i_] = v*oobbuf[i,i_];
+                    }
+                    if( ensemble.issoftmax )
+                    {
+                        dy[0] = xy[i,nin];
+                    }
+                    else
+                    {
+                        i1_ = (nin) - (0);
+                        for(i_=0; i_<=nout-1;i_++)
+                        {
+                            dy[i_] = v*xy[i,i_+i1_];
+                        }
+                    }
+                    bdss.dserraccumulate(ref dsbuf, ref y, ref dy);
+                }
+            }
+            bdss.dserrfinish(ref dsbuf);
+            ooberrors.relclserror = dsbuf[0];
+            ooberrors.avgce = dsbuf[1];
+            ooberrors.rmserror = dsbuf[2];
+            ooberrors.avgerror = dsbuf[3];
+            ooberrors.avgrelerror = dsbuf[4];
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlptrain.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlptrain.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/mlptrain.cs	(revision 2645)
@@ -0,0 +1,1200 @@
+/*************************************************************************
+Copyright (c) 2007-2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class mlptrain
+    {
+        /*************************************************************************
+        Training report:
+            * NGrad     - number of gradient calculations
+            * NHess     - number of Hessian calculations
+            * NCholesky - number of Cholesky decompositions
+        *************************************************************************/
+        public struct mlpreport
+        {
+            public int ngrad;
+            public int nhess;
+            public int ncholesky;
+        };
+
+
+        /*************************************************************************
+        Cross-validation estimates of generalization error
+        *************************************************************************/
+        public struct mlpcvreport
+        {
+            public double relclserror;
+            public double avgce;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+        };
+
+
+
+
+        public const double mindecay = 0.001;
+
+
+        /*************************************************************************
+        Neural network training  using  modified  Levenberg-Marquardt  with  exact
+        Hessian calculation and regularization. Subroutine trains  neural  network
+        with restarts from random positions. Algorithm is well  suited  for  small
+        and medium scale problems (hundreds of weights).
+
+        INPUT PARAMETERS:
+            Network     -   neural network with initialized geometry
+            XY          -   training set
+            NPoints     -   training set size
+            Decay       -   weight decay constant, >=0.001
+                            Decay term 'Decay*||Weights||^2' is added to error
+                            function.
+                            If you don't know what Decay to choose, use 0.001.
+            Restarts    -   number of restarts from random position, >0.
+                            If you don't know what Restarts to choose, use 2.
+
+        OUTPUT PARAMETERS:
+            Network     -   trained neural network.
+            Info        -   return code:
+                            * -9, if internal matrix inverse subroutine failed
+                            * -2, if there is a point with class number
+                                  outside of [0..NOut-1].
+                            * -1, if wrong parameters specified
+                                  (NPoints<0, Restarts<1).
+                            *  2, if task has been solved.
+            Rep         -   training report
+
+          -- ALGLIB --
+             Copyright 10.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlptrainlm(ref mlpbase.multilayerperceptron network,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            ref int info,
+            ref mlpreport rep)
+        {
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double lmftol = 0;
+            double lmsteptol = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int mx = 0;
+            double v = 0;
+            double e = 0;
+            double enew = 0;
+            double xnorm2 = 0;
+            double stepnorm = 0;
+            double[] g = new double[0];
+            double[] d = new double[0];
+            double[,] h = new double[0,0];
+            double[,] hmod = new double[0,0];
+            double[,] z = new double[0,0];
+            bool spd = new bool();
+            double nu = 0;
+            double lambda = 0;
+            double lambdaup = 0;
+            double lambdadown = 0;
+            int cvcnt = 0;
+            double cvrelcnt = 0;
+            lbfgs.lbfgsreport internalrep = new lbfgs.lbfgsreport();
+            lbfgs.lbfgsstate state = new lbfgs.lbfgsstate();
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[] wbase = new double[0];
+            double wstep = 0;
+            double[] wdir = new double[0];
+            double[] wt = new double[0];
+            double[] wx = new double[0];
+            int pass = 0;
+            double[] wbest = new double[0];
+            double ebest = 0;
+            int i_ = 0;
+
+            mlpbase.mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            lambdaup = 10;
+            lambdadown = 0.3;
+            lmftol = 0.001;
+            lmsteptol = 0.001;
+            
+            //
+            // Test for inputs
+            //
+            if( npoints<=0 | restarts<1 )
+            {
+                info = -1;
+                return;
+            }
+            if( mlpbase.mlpissoftmax(ref network) )
+            {
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( (int)Math.Round(xy[i,nin])<0 | (int)Math.Round(xy[i,nin])>=nout )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+            }
+            decay = Math.Max(decay, mindecay);
+            info = 2;
+            
+            //
+            // Initialize data
+            //
+            rep.ngrad = 0;
+            rep.nhess = 0;
+            rep.ncholesky = 0;
+            
+            //
+            // General case.
+            // Prepare task and network. Allocate space.
+            //
+            mlpbase.mlpinitpreprocessor(ref network, ref xy, npoints);
+            g = new double[wcount-1+1];
+            h = new double[wcount-1+1, wcount-1+1];
+            hmod = new double[wcount-1+1, wcount-1+1];
+            wbase = new double[wcount-1+1];
+            wdir = new double[wcount-1+1];
+            wbest = new double[wcount-1+1];
+            wt = new double[wcount-1+1];
+            wx = new double[wcount-1+1];
+            ebest = AP.Math.MaxRealNumber;
+            
+            //
+            // Multiple passes
+            //
+            for(pass=1; pass<=restarts; pass++)
+            {
+                
+                //
+                // Initialize weights
+                //
+                mlpbase.mlprandomize(ref network);
+                
+                //
+                // First stage of the hybrid algorithm: LBFGS
+                //
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    wbase[i_] = network.weights[i_];
+                }
+                lbfgs.minlbfgs(wcount, Math.Min(wcount, 5), ref wbase, 0.0, 0.0, 0.0, Math.Max(25, wcount), 0, ref state);
+                while( lbfgs.minlbfgsiteration(ref state) )
+                {
+                    
+                    //
+                    // gradient
+                    //
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        network.weights[i_] = state.x[i_];
+                    }
+                    mlpbase.mlpgradbatch(ref network, ref xy, npoints, ref state.f, ref state.g);
+                    
+                    //
+                    // weight decay
+                    //
+                    v = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        v += network.weights[i_]*network.weights[i_];
+                    }
+                    state.f = state.f+0.5*decay*v;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        state.g[i_] = state.g[i_] + decay*network.weights[i_];
+                    }
+                    
+                    //
+                    // next iteration
+                    //
+                    rep.ngrad = rep.ngrad+1;
+                }
+                lbfgs.minlbfgsresults(ref state, ref wbase, ref internalrep);
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    network.weights[i_] = wbase[i_];
+                }
+                
+                //
+                // Second stage of the hybrid algorithm: LM
+                //
+                // Initialize H with identity matrix,
+                // G with gradient,
+                // E with regularized error.
+                //
+                mlpbase.mlphessianbatch(ref network, ref xy, npoints, ref e, ref g, ref h);
+                v = 0.0;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    v += network.weights[i_]*network.weights[i_];
+                }
+                e = e+0.5*decay*v;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    g[i_] = g[i_] + decay*network.weights[i_];
+                }
+                for(k=0; k<=wcount-1; k++)
+                {
+                    h[k,k] = h[k,k]+decay;
+                }
+                rep.nhess = rep.nhess+1;
+                lambda = 0.001;
+                nu = 2;
+                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,i_] = h[i,i_];
+                        }
+                        hmod[i,i] = hmod[i,i]+lambda;
+                    }
+                    spd = cholesky.spdmatrixcholesky(ref hmod, wcount, true);
+                    rep.ncholesky = rep.ncholesky+1;
+                    if( !spd )
+                    {
+                        lambda = lambda*lambdaup*nu;
+                        nu = nu*2;
+                        continue;
+                    }
+                    if( !spdsolve.spdmatrixcholeskysolve(ref hmod, g, wcount, true, ref wdir) )
+                    {
+                        lambda = lambda*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.weights[i_] = network.weights[i_] + wdir[i_];
+                    }
+                    xnorm2 = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        xnorm2 += network.weights[i_]*network.weights[i_];
+                    }
+                    stepnorm = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        stepnorm += wdir[i_]*wdir[i_];
+                    }
+                    stepnorm = Math.Sqrt(stepnorm);
+                    enew = mlpbase.mlperror(ref network, ref xy, npoints)+0.5*decay*xnorm2;
+                    if( (double)(stepnorm)<(double)(lmsteptol*(1+Math.Sqrt(xnorm2))) )
+                    {
+                        break;
+                    }
+                    if( (double)(enew)>(double)(e) )
+                    {
+                        lambda = lambda*lambdaup*nu;
+                        nu = nu*2;
+                        continue;
+                    }
+                    
+                    //
+                    // Optimize using inv(cholesky(H)) as preconditioner
+                    //
+                    if( !trinverse.rmatrixtrinverse(ref hmod, wcount, true, false) )
+                    {
+                        
+                        //
+                        // if matrix can't be inverted then exit with errors
+                        // TODO: make WCount steps in direction suggested by HMod
+                        //
+                        info = -9;
+                        return;
+                    }
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        wbase[i_] = network.weights[i_];
+                    }
+                    for(i=0; i<=wcount-1; i++)
+                    {
+                        wt[i] = 0;
+                    }
+                    lbfgs.minlbfgs(wcount, wcount, ref wt, 0.0, 0.0, 0.0, 5, 0, ref state);
+                    while( lbfgs.minlbfgsiteration(ref state) )
+                    {
+                        
+                        //
+                        // gradient
+                        //
+                        for(i=0; i<=wcount-1; i++)
+                        {
+                            v = 0.0;
+                            for(i_=i; i_<=wcount-1;i_++)
+                            {
+                                v += state.x[i_]*hmod[i,i_];
+                            }
+                            network.weights[i] = wbase[i]+v;
+                        }
+                        mlpbase.mlpgradbatch(ref network, ref xy, npoints, ref state.f, ref g);
+                        for(i=0; i<=wcount-1; i++)
+                        {
+                            state.g[i] = 0;
+                        }
+                        for(i=0; i<=wcount-1; i++)
+                        {
+                            v = g[i];
+                            for(i_=i; i_<=wcount-1;i_++)
+                            {
+                                state.g[i_] = state.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.weights[i_]*network.weights[i_];
+                        }
+                        state.f = state.f+0.5*decay*v;
+                        for(i=0; i<=wcount-1; i++)
+                        {
+                            v = decay*network.weights[i];
+                            for(i_=i; i_<=wcount-1;i_++)
+                            {
+                                state.g[i_] = state.g[i_] + v*hmod[i,i_];
+                            }
+                        }
+                        
+                        //
+                        // next iteration
+                        //
+                        rep.ngrad = rep.ngrad+1;
+                    }
+                    lbfgs.minlbfgsresults(ref state, ref wt, ref 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.weights[i] = wbase[i]+v;
+                    }
+                    mlpbase.mlphessianbatch(ref network, ref xy, npoints, ref e, ref g, ref h);
+                    v = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        v += network.weights[i_]*network.weights[i_];
+                    }
+                    e = e+0.5*decay*v;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        g[i_] = g[i_] + decay*network.weights[i_];
+                    }
+                    for(k=0; k<=wcount-1; k++)
+                    {
+                        h[k,k] = h[k,k]+decay;
+                    }
+                    rep.nhess = rep.nhess+1;
+                    
+                    //
+                    // Update lambda
+                    //
+                    lambda = lambda*lambdadown;
+                    nu = 2;
+                }
+                
+                //
+                // update WBest
+                //
+                v = 0.0;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    v += network.weights[i_]*network.weights[i_];
+                }
+                e = 0.5*decay*v+mlpbase.mlperror(ref network, ref xy, npoints);
+                if( (double)(e)<(double)(ebest) )
+                {
+                    ebest = e;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        wbest[i_] = network.weights[i_];
+                    }
+                }
+            }
+            
+            //
+            // copy WBest to output
+            //
+            for(i_=0; i_<=wcount-1;i_++)
+            {
+                network.weights[i_] = wbest[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Neural  network  training  using  L-BFGS  algorithm  with  regularization.
+        Subroutine  trains  neural  network  with  restarts from random positions.
+        Algorithm  is  well  suited  for  problems  of  any dimensionality (memory
+        requirements and step complexity are linear by weights number).
+
+        INPUT PARAMETERS:
+            Network     -   neural network with initialized geometry
+            XY          -   training set
+            NPoints     -   training set size
+            Decay       -   weight decay constant, >=0.001
+                            Decay term 'Decay*||Weights||^2' is added to error
+                            function.
+                            If you don't know what Decay to choose, use 0.001.
+            Restarts    -   number of restarts from random position, >0.
+                            If you don't know what Restarts to choose, use 2.
+            WStep       -   stopping criterion. Algorithm stops if  step  size  is
+                            less than WStep. Recommended value - 0.01.  Zero  step
+                            size means stopping after MaxIts iterations.
+            MaxIts      -   stopping   criterion.  Algorithm  stops  after  MaxIts
+                            iterations (NOT gradient  calculations).  Zero  MaxIts
+                            means stopping when step is sufficiently small.
+
+        OUTPUT PARAMETERS:
+            Network     -   trained neural network.
+            Info        -   return code:
+                            * -8, if both WStep=0 and MaxIts=0
+                            * -2, if there is a point with class number
+                                  outside of [0..NOut-1].
+                            * -1, if wrong parameters specified
+                                  (NPoints<0, Restarts<1).
+                            *  2, if task has been solved.
+            Rep         -   training report
+
+          -- ALGLIB --
+             Copyright 09.12.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlptrainlbfgs(ref mlpbase.multilayerperceptron network,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            double wstep,
+            int maxits,
+            ref int info,
+            ref mlpreport rep)
+        {
+            int i = 0;
+            int j = 0;
+            int pass = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double[] w = new double[0];
+            double[] wbest = new double[0];
+            double e = 0;
+            double v = 0;
+            double ebest = 0;
+            lbfgs.lbfgsreport internalrep = new lbfgs.lbfgsreport();
+            lbfgs.lbfgsstate state = new lbfgs.lbfgsstate();
+            int i_ = 0;
+
+            
+            //
+            // Test inputs, parse flags, read network geometry
+            //
+            if( (double)(wstep)==(double)(0) & maxits==0 )
+            {
+                info = -8;
+                return;
+            }
+            if( npoints<=0 | restarts<1 | (double)(wstep)<(double)(0) | maxits<0 )
+            {
+                info = -1;
+                return;
+            }
+            mlpbase.mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            if( mlpbase.mlpissoftmax(ref network) )
+            {
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( (int)Math.Round(xy[i,nin])<0 | (int)Math.Round(xy[i,nin])>=nout )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+            }
+            decay = Math.Max(decay, mindecay);
+            info = 2;
+            
+            //
+            // Prepare
+            //
+            mlpbase.mlpinitpreprocessor(ref network, ref xy, npoints);
+            w = new double[wcount-1+1];
+            wbest = new double[wcount-1+1];
+            ebest = AP.Math.MaxRealNumber;
+            
+            //
+            // Multiple starts
+            //
+            rep.ncholesky = 0;
+            rep.nhess = 0;
+            rep.ngrad = 0;
+            for(pass=1; pass<=restarts; pass++)
+            {
+                
+                //
+                // Process
+                //
+                mlpbase.mlprandomize(ref network);
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    w[i_] = network.weights[i_];
+                }
+                lbfgs.minlbfgs(wcount, Math.Min(wcount, 50), ref w, 0.0, 0.0, wstep, maxits, 0, ref state);
+                while( lbfgs.minlbfgsiteration(ref state) )
+                {
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        network.weights[i_] = state.x[i_];
+                    }
+                    mlpbase.mlpgradnbatch(ref network, ref xy, npoints, ref state.f, ref state.g);
+                    v = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        v += network.weights[i_]*network.weights[i_];
+                    }
+                    state.f = state.f+0.5*decay*v;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        state.g[i_] = state.g[i_] + decay*network.weights[i_];
+                    }
+                    rep.ngrad = rep.ngrad+1;
+                }
+                lbfgs.minlbfgsresults(ref state, ref w, ref internalrep);
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    network.weights[i_] = w[i_];
+                }
+                
+                //
+                // Compare with best
+                //
+                v = 0.0;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    v += network.weights[i_]*network.weights[i_];
+                }
+                e = mlpbase.mlperrorn(ref network, ref xy, npoints)+0.5*decay*v;
+                if( (double)(e)<(double)(ebest) )
+                {
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        wbest[i_] = network.weights[i_];
+                    }
+                    ebest = e;
+                }
+            }
+            
+            //
+            // The best network
+            //
+            for(i_=0; i_<=wcount-1;i_++)
+            {
+                network.weights[i_] = wbest[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Neural network training using early stopping (base algorithm - L-BFGS with
+        regularization).
+
+        INPUT PARAMETERS:
+            Network     -   neural network with initialized geometry
+            TrnXY       -   training set
+            TrnSize     -   training set size
+            ValXY       -   validation set
+            ValSize     -   validation 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:
+                            * -2, if there is a point with class number
+                                  outside of [0..NOut-1].
+                            * -1, if wrong parameters specified
+                                  (NPoints<0, Restarts<1, ...).
+                            *  2, task has been solved, stopping  criterion  met -
+                                  sufficiently small step size.  Not expected  (we
+                                  use  EARLY  stopping)  but  possible  and not an
+                                  error.
+                            *  6, task has been solved, stopping  criterion  met -
+                                  increasing of validation set error.
+            Rep         -   training report
+
+        NOTE:
+
+        Algorithm stops if validation set error increases for  a  long  enough  or
+        step size is small enought  (there  are  task  where  validation  set  may
+        decrease for eternity). In any case solution returned corresponds  to  the
+        minimum of validation set error.
+
+          -- ALGLIB --
+             Copyright 10.03.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlptraines(ref mlpbase.multilayerperceptron network,
+            ref double[,] trnxy,
+            int trnsize,
+            ref double[,] valxy,
+            int valsize,
+            double decay,
+            int restarts,
+            ref int info,
+            ref mlpreport rep)
+        {
+            int i = 0;
+            int j = 0;
+            int pass = 0;
+            int nin = 0;
+            int nout = 0;
+            int wcount = 0;
+            double[] w = new double[0];
+            double[] wbest = new double[0];
+            double e = 0;
+            double v = 0;
+            double ebest = 0;
+            double[] wfinal = new double[0];
+            double efinal = 0;
+            int itbest = 0;
+            lbfgs.lbfgsreport internalrep = new lbfgs.lbfgsreport();
+            lbfgs.lbfgsstate state = new lbfgs.lbfgsstate();
+            double wstep = 0;
+            int i_ = 0;
+
+            wstep = 0.001;
+            
+            //
+            // Test inputs, parse flags, read network geometry
+            //
+            if( trnsize<=0 | valsize<=0 | restarts<1 | (double)(decay)<(double)(0) )
+            {
+                info = -1;
+                return;
+            }
+            mlpbase.mlpproperties(ref network, ref nin, ref nout, ref wcount);
+            if( mlpbase.mlpissoftmax(ref network) )
+            {
+                for(i=0; i<=trnsize-1; i++)
+                {
+                    if( (int)Math.Round(trnxy[i,nin])<0 | (int)Math.Round(trnxy[i,nin])>=nout )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+                for(i=0; i<=valsize-1; i++)
+                {
+                    if( (int)Math.Round(valxy[i,nin])<0 | (int)Math.Round(valxy[i,nin])>=nout )
+                    {
+                        info = -2;
+                        return;
+                    }
+                }
+            }
+            info = 2;
+            
+            //
+            // Prepare
+            //
+            mlpbase.mlpinitpreprocessor(ref network, ref trnxy, trnsize);
+            w = new double[wcount-1+1];
+            wbest = new double[wcount-1+1];
+            wfinal = new double[wcount-1+1];
+            efinal = AP.Math.MaxRealNumber;
+            for(i=0; i<=wcount-1; i++)
+            {
+                wfinal[i] = 0;
+            }
+            
+            //
+            // Multiple starts
+            //
+            rep.ncholesky = 0;
+            rep.nhess = 0;
+            rep.ngrad = 0;
+            for(pass=1; pass<=restarts; pass++)
+            {
+                
+                //
+                // Process
+                //
+                mlpbase.mlprandomize(ref network);
+                ebest = mlpbase.mlperror(ref network, ref valxy, valsize);
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    wbest[i_] = network.weights[i_];
+                }
+                itbest = 0;
+                for(i_=0; i_<=wcount-1;i_++)
+                {
+                    w[i_] = network.weights[i_];
+                }
+                lbfgs.minlbfgs(wcount, Math.Min(wcount, 50), ref w, 0.0, 0.0, wstep, 0, 0, ref state);
+                while( lbfgs.minlbfgsiteration(ref state) )
+                {
+                    
+                    //
+                    // Calculate gradient
+                    //
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        network.weights[i_] = state.x[i_];
+                    }
+                    mlpbase.mlpgradnbatch(ref network, ref trnxy, trnsize, ref state.f, ref state.g);
+                    v = 0.0;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        v += network.weights[i_]*network.weights[i_];
+                    }
+                    state.f = state.f+0.5*decay*v;
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        state.g[i_] = state.g[i_] + decay*network.weights[i_];
+                    }
+                    rep.ngrad = rep.ngrad+1;
+                    
+                    //
+                    // Validation set
+                    //
+                    if( state.xupdated )
+                    {
+                        for(i_=0; i_<=wcount-1;i_++)
+                        {
+                            network.weights[i_] = w[i_];
+                        }
+                        e = mlpbase.mlperror(ref network, ref valxy, valsize);
+                        if( (double)(e)<(double)(ebest) )
+                        {
+                            ebest = e;
+                            for(i_=0; i_<=wcount-1;i_++)
+                            {
+                                wbest[i_] = network.weights[i_];
+                            }
+                            itbest = internalrep.iterationscount;
+                        }
+                        if( internalrep.iterationscount>30 & (double)(internalrep.iterationscount)>(double)(1.5*itbest) )
+                        {
+                            info = 6;
+                            break;
+                        }
+                    }
+                }
+                lbfgs.minlbfgsresults(ref state, ref w, ref internalrep);
+                
+                //
+                // Compare with final answer
+                //
+                if( (double)(ebest)<(double)(efinal) )
+                {
+                    for(i_=0; i_<=wcount-1;i_++)
+                    {
+                        wfinal[i_] = wbest[i_];
+                    }
+                    efinal = ebest;
+                }
+            }
+            
+            //
+            // The best network
+            //
+            for(i_=0; i_<=wcount-1;i_++)
+            {
+                network.weights[i_] = wfinal[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Cross-validation estimate of generalization error.
+
+        Base algorithm - L-BFGS.
+
+        INPUT PARAMETERS:
+            Network     -   neural network with initialized geometry.   Network is
+                            not changed during cross-validation -  it is used only
+                            as a representative of its architecture.
+            XY          -   training set.
+            SSize       -   training set size
+            Decay       -   weight  decay, same as in MLPTrainLBFGS
+            Restarts    -   number of restarts, >0.
+                            restarts are counted for each partition separately, so
+                            total number of restarts will be Restarts*FoldsCount.
+            WStep       -   stopping criterion, same as in MLPTrainLBFGS
+            MaxIts      -   stopping criterion, same as in MLPTrainLBFGS
+            FoldsCount  -   number of folds in k-fold cross-validation,
+                            2<=FoldsCount<=SSize.
+                            recommended value: 10.
+
+        OUTPUT PARAMETERS:
+            Info        -   return code, same as in MLPTrainLBFGS
+            Rep         -   report, same as in MLPTrainLM/MLPTrainLBFGS
+            CVRep       -   generalization error estimates
+
+          -- ALGLIB --
+             Copyright 09.12.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpkfoldcvlbfgs(ref mlpbase.multilayerperceptron network,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            double wstep,
+            int maxits,
+            int foldscount,
+            ref int info,
+            ref mlpreport rep,
+            ref mlpcvreport cvrep)
+        {
+            mlpkfoldcvgeneral(ref network, ref xy, npoints, decay, restarts, foldscount, false, wstep, maxits, ref info, ref rep, ref cvrep);
+        }
+
+
+        /*************************************************************************
+        Cross-validation estimate of generalization error.
+
+        Base algorithm - Levenberg-Marquardt.
+
+        INPUT PARAMETERS:
+            Network     -   neural network with initialized geometry.   Network is
+                            not changed during cross-validation -  it is used only
+                            as a representative of its architecture.
+            XY          -   training set.
+            SSize       -   training set size
+            Decay       -   weight  decay, same as in MLPTrainLBFGS
+            Restarts    -   number of restarts, >0.
+                            restarts are counted for each partition separately, so
+                            total number of restarts will be Restarts*FoldsCount.
+            FoldsCount  -   number of folds in k-fold cross-validation,
+                            2<=FoldsCount<=SSize.
+                            recommended value: 10.
+
+        OUTPUT PARAMETERS:
+            Info        -   return code, same as in MLPTrainLBFGS
+            Rep         -   report, same as in MLPTrainLM/MLPTrainLBFGS
+            CVRep       -   generalization error estimates
+
+          -- ALGLIB --
+             Copyright 09.12.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void mlpkfoldcvlm(ref mlpbase.multilayerperceptron network,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            int foldscount,
+            ref int info,
+            ref mlpreport rep,
+            ref mlpcvreport cvrep)
+        {
+            mlpkfoldcvgeneral(ref network, ref xy, npoints, decay, restarts, foldscount, true, 0.0, 0, ref info, ref rep, ref cvrep);
+        }
+
+
+        /*************************************************************************
+        Internal cross-validation subroutine
+        *************************************************************************/
+        private static void mlpkfoldcvgeneral(ref mlpbase.multilayerperceptron n,
+            ref double[,] xy,
+            int npoints,
+            double decay,
+            int restarts,
+            int foldscount,
+            bool lmalgorithm,
+            double wstep,
+            int maxits,
+            ref int info,
+            ref mlpreport rep,
+            ref mlpcvreport cvrep)
+        {
+            int i = 0;
+            int fold = 0;
+            int j = 0;
+            int k = 0;
+            mlpbase.multilayerperceptron network = new mlpbase.multilayerperceptron();
+            int nin = 0;
+            int nout = 0;
+            int rowlen = 0;
+            int wcount = 0;
+            int nclasses = 0;
+            int tssize = 0;
+            int cvssize = 0;
+            double[,] cvset = new double[0,0];
+            double[,] testset = new double[0,0];
+            int[] folds = new int[0];
+            int relcnt = 0;
+            mlpreport internalrep = new mlpreport();
+            double[] x = new double[0];
+            double[] y = new double[0];
+            int i_ = 0;
+
+            
+            //
+            // Read network geometry, test parameters
+            //
+            mlpbase.mlpproperties(ref n, ref nin, ref nout, ref wcount);
+            if( mlpbase.mlpissoftmax(ref n) )
+            {
+                nclasses = nout;
+                rowlen = nin+1;
+            }
+            else
+            {
+                nclasses = -nout;
+                rowlen = nin+nout;
+            }
+            if( npoints<=0 | foldscount<2 | foldscount>npoints )
+            {
+                info = -1;
+                return;
+            }
+            mlpbase.mlpcopy(ref n, ref network);
+            
+            //
+            // K-fold out cross-validation.
+            // First, estimate generalization error
+            //
+            testset = new double[npoints-1+1, rowlen-1+1];
+            cvset = new double[npoints-1+1, rowlen-1+1];
+            x = new double[nin-1+1];
+            y = new double[nout-1+1];
+            mlpkfoldsplit(ref xy, npoints, nclasses, foldscount, false, ref folds);
+            cvrep.relclserror = 0;
+            cvrep.avgce = 0;
+            cvrep.rmserror = 0;
+            cvrep.avgerror = 0;
+            cvrep.avgrelerror = 0;
+            rep.ngrad = 0;
+            rep.nhess = 0;
+            rep.ncholesky = 0;
+            relcnt = 0;
+            for(fold=0; fold<=foldscount-1; fold++)
+            {
+                
+                //
+                // Separate set
+                //
+                tssize = 0;
+                cvssize = 0;
+                for(i=0; i<=npoints-1; i++)
+                {
+                    if( folds[i]==fold )
+                    {
+                        for(i_=0; i_<=rowlen-1;i_++)
+                        {
+                            testset[tssize,i_] = xy[i,i_];
+                        }
+                        tssize = tssize+1;
+                    }
+                    else
+                    {
+                        for(i_=0; i_<=rowlen-1;i_++)
+                        {
+                            cvset[cvssize,i_] = xy[i,i_];
+                        }
+                        cvssize = cvssize+1;
+                    }
+                }
+                
+                //
+                // Train on CV training set
+                //
+                if( lmalgorithm )
+                {
+                    mlptrainlm(ref network, ref cvset, cvssize, decay, restarts, ref info, ref internalrep);
+                }
+                else
+                {
+                    mlptrainlbfgs(ref network, ref cvset, cvssize, decay, restarts, wstep, maxits, ref info, ref internalrep);
+                }
+                if( info<0 )
+                {
+                    cvrep.relclserror = 0;
+                    cvrep.avgce = 0;
+                    cvrep.rmserror = 0;
+                    cvrep.avgerror = 0;
+                    cvrep.avgrelerror = 0;
+                    return;
+                }
+                rep.ngrad = rep.ngrad+internalrep.ngrad;
+                rep.nhess = rep.nhess+internalrep.nhess;
+                rep.ncholesky = rep.ncholesky+internalrep.ncholesky;
+                
+                //
+                // Estimate error using CV test set
+                //
+                if( mlpbase.mlpissoftmax(ref network) )
+                {
+                    
+                    //
+                    // classification-only code
+                    //
+                    cvrep.relclserror = cvrep.relclserror+mlpbase.mlpclserror(ref network, ref testset, tssize);
+                    cvrep.avgce = cvrep.avgce+mlpbase.mlperrorn(ref network, ref testset, tssize);
+                }
+                for(i=0; i<=tssize-1; i++)
+                {
+                    for(i_=0; i_<=nin-1;i_++)
+                    {
+                        x[i_] = testset[i,i_];
+                    }
+                    mlpbase.mlpprocess(ref network, ref x, ref y);
+                    if( mlpbase.mlpissoftmax(ref network) )
+                    {
+                        
+                        //
+                        // Classification-specific code
+                        //
+                        k = (int)Math.Round(testset[i,nin]);
+                        for(j=0; j<=nout-1; j++)
+                        {
+                            if( j==k )
+                            {
+                                cvrep.rmserror = cvrep.rmserror+AP.Math.Sqr(y[j]-1);
+                                cvrep.avgerror = cvrep.avgerror+Math.Abs(y[j]-1);
+                                cvrep.avgrelerror = cvrep.avgrelerror+Math.Abs(y[j]-1);
+                                relcnt = relcnt+1;
+                            }
+                            else
+                            {
+                                cvrep.rmserror = cvrep.rmserror+AP.Math.Sqr(y[j]);
+                                cvrep.avgerror = cvrep.avgerror+Math.Abs(y[j]);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Regression-specific code
+                        //
+                        for(j=0; j<=nout-1; j++)
+                        {
+                            cvrep.rmserror = cvrep.rmserror+AP.Math.Sqr(y[j]-testset[i,nin+j]);
+                            cvrep.avgerror = cvrep.avgerror+Math.Abs(y[j]-testset[i,nin+j]);
+                            if( (double)(testset[i,nin+j])!=(double)(0) )
+                            {
+                                cvrep.avgrelerror = cvrep.avgrelerror+Math.Abs((y[j]-testset[i,nin+j])/testset[i,nin+j]);
+                                relcnt = relcnt+1;
+                            }
+                        }
+                    }
+                }
+            }
+            if( mlpbase.mlpissoftmax(ref network) )
+            {
+                cvrep.relclserror = cvrep.relclserror/npoints;
+                cvrep.avgce = cvrep.avgce/(Math.Log(2)*npoints);
+            }
+            cvrep.rmserror = Math.Sqrt(cvrep.rmserror/(npoints*nout));
+            cvrep.avgerror = cvrep.avgerror/(npoints*nout);
+            cvrep.avgrelerror = cvrep.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.
+        *************************************************************************/
+        private static void mlpkfoldsplit(ref double[,] xy,
+            int npoints,
+            int nclasses,
+            int foldscount,
+            bool stratifiedsplits,
+            ref int[] folds)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+
+            
+            //
+            // test parameters
+            //
+            System.Diagnostics.Debug.Assert(npoints>0, "MLPKFoldSplit: wrong NPoints!");
+            System.Diagnostics.Debug.Assert(nclasses>1 | nclasses<0, "MLPKFoldSplit: wrong NClasses!");
+            System.Diagnostics.Debug.Assert(foldscount>=2 & foldscount<=npoints, "MLPKFoldSplit: wrong FoldsCount!");
+            System.Diagnostics.Debug.Assert(!stratifiedsplits, "MLPKFoldSplit: stratified splits are not supported!");
+            
+            //
+            // Folds
+            //
+            folds = new int[npoints-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                folds[i] = i*foldscount/npoints;
+            }
+            for(i=0; i<=npoints-2; i++)
+            {
+                j = i+AP.Math.RandomInteger(npoints-i);
+                if( j!=i )
+                {
+                    k = folds[i];
+                    folds[i] = folds[j];
+                    folds[j] = k;
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/nearunityunit.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/nearunityunit.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/nearunityunit.cs	(revision 2645)
@@ -0,0 +1,93 @@
+
+using System;
+
+namespace alglib
+{
+    public class nearunityunit
+    {
+        public static double log1p(double x)
+        {
+            double result = 0;
+            double z = 0;
+            double lp = 0;
+            double lq = 0;
+
+            z = 1.0+x;
+            if( (double)(z)<(double)(0.70710678118654752440) | (double)(z)>(double)(1.41421356237309504880) )
+            {
+                result = Math.Log(z);
+                return result;
+            }
+            z = x*x;
+            lp = 4.5270000862445199635215E-5;
+            lp = lp*x+4.9854102823193375972212E-1;
+            lp = lp*x+6.5787325942061044846969E0;
+            lp = lp*x+2.9911919328553073277375E1;
+            lp = lp*x+6.0949667980987787057556E1;
+            lp = lp*x+5.7112963590585538103336E1;
+            lp = lp*x+2.0039553499201281259648E1;
+            lq = 1.0000000000000000000000E0;
+            lq = lq*x+1.5062909083469192043167E1;
+            lq = lq*x+8.3047565967967209469434E1;
+            lq = lq*x+2.2176239823732856465394E2;
+            lq = lq*x+3.0909872225312059774938E2;
+            lq = lq*x+2.1642788614495947685003E2;
+            lq = lq*x+6.0118660497603843919306E1;
+            z = -(0.5*z)+x*(z*lp/lq);
+            result = x+z;
+            return result;
+        }
+
+
+        public static double expm1(double x)
+        {
+            double result = 0;
+            double r = 0;
+            double xx = 0;
+            double ep = 0;
+            double eq = 0;
+
+            if( (double)(x)<(double)(-0.5) | (double)(x)>(double)(0.5) )
+            {
+                result = Math.Exp(x)-1.0;
+                return result;
+            }
+            xx = x*x;
+            ep = 1.2617719307481059087798E-4;
+            ep = ep*xx+3.0299440770744196129956E-2;
+            ep = ep*xx+9.9999999999999999991025E-1;
+            eq = 3.0019850513866445504159E-6;
+            eq = eq*xx+2.5244834034968410419224E-3;
+            eq = eq*xx+2.2726554820815502876593E-1;
+            eq = eq*xx+2.0000000000000000000897E0;
+            r = x*ep;
+            r = r/(eq-r);
+            result = r+r;
+            return result;
+        }
+
+
+        public static double cosm1(double x)
+        {
+            double result = 0;
+            double xx = 0;
+            double c = 0;
+
+            if( (double)(x)<(double)(-(0.25*Math.PI)) | (double)(x)>(double)(0.25*Math.PI) )
+            {
+                result = Math.Cos(x)-1;
+                return result;
+            }
+            xx = x*x;
+            c = 4.7377507964246204691685E-14;
+            c = c*xx-1.1470284843425359765671E-11;
+            c = c*xx+2.0876754287081521758361E-9;
+            c = c*xx-2.7557319214999787979814E-7;
+            c = c*xx+2.4801587301570552304991E-5;
+            c = c*xx-1.3888888888888872993737E-3;
+            c = c*xx+4.1666666666666666609054E-2;
+            result = -(0.5*xx)+xx*xx*c;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/normaldistr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/normaldistr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/normaldistr.cs	(revision 2645)
@@ -0,0 +1,367 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class normaldistr
+    {
+        /*************************************************************************
+        Error function
+
+        The integral is
+
+                                  x
+                                   -
+                        2         | |          2
+          erf(x)  =  --------     |    exp( - t  ) dt.
+                     sqrt(pi)   | |
+                                 -
+                                  0
+
+        For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise
+        erf(x) = 1 - erfc(x).
+
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,1         30000       3.7e-16     1.0e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double erf(double x)
+        {
+            double result = 0;
+            double xsq = 0;
+            double s = 0;
+            double p = 0;
+            double q = 0;
+
+            s = Math.Sign(x);
+            x = Math.Abs(x);
+            if( (double)(x)<(double)(0.5) )
+            {
+                xsq = x*x;
+                p = 0.007547728033418631287834;
+                p = 0.288805137207594084924010+xsq*p;
+                p = 14.3383842191748205576712+xsq*p;
+                p = 38.0140318123903008244444+xsq*p;
+                p = 3017.82788536507577809226+xsq*p;
+                p = 7404.07142710151470082064+xsq*p;
+                p = 80437.3630960840172832162+xsq*p;
+                q = 0.0;
+                q = 1.00000000000000000000000+xsq*q;
+                q = 38.0190713951939403753468+xsq*q;
+                q = 658.070155459240506326937+xsq*q;
+                q = 6379.60017324428279487120+xsq*q;
+                q = 34216.5257924628539769006+xsq*q;
+                q = 80437.3630960840172826266+xsq*q;
+                result = s*1.1283791670955125738961589031*x*p/q;
+                return result;
+            }
+            if( (double)(x)>=(double)(10) )
+            {
+                result = s;
+                return result;
+            }
+            result = s*(1-erfc(x));
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complementary error function
+
+         1 - erf(x) =
+
+                                  inf.
+                                    -
+                         2         | |          2
+          erfc(x)  =  --------     |    exp( - t  ) dt
+                      sqrt(pi)   | |
+                                  -
+                                   x
+
+
+        For small x, erfc(x) = 1 - erf(x); otherwise rational
+        approximations are computed.
+
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,26.6417   30000       5.7e-14     1.5e-14
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double erfc(double x)
+        {
+            double result = 0;
+            double p = 0;
+            double q = 0;
+
+            if( (double)(x)<(double)(0) )
+            {
+                result = 2-erfc(-x);
+                return result;
+            }
+            if( (double)(x)<(double)(0.5) )
+            {
+                result = 1.0-erf(x);
+                return result;
+            }
+            if( (double)(x)>=(double)(10) )
+            {
+                result = 0;
+                return result;
+            }
+            p = 0.0;
+            p = 0.5641877825507397413087057563+x*p;
+            p = 9.675807882987265400604202961+x*p;
+            p = 77.08161730368428609781633646+x*p;
+            p = 368.5196154710010637133875746+x*p;
+            p = 1143.262070703886173606073338+x*p;
+            p = 2320.439590251635247384768711+x*p;
+            p = 2898.0293292167655611275846+x*p;
+            p = 1826.3348842295112592168999+x*p;
+            q = 1.0;
+            q = 17.14980943627607849376131193+x*q;
+            q = 137.1255960500622202878443578+x*q;
+            q = 661.7361207107653469211984771+x*q;
+            q = 2094.384367789539593790281779+x*q;
+            q = 4429.612803883682726711528526+x*q;
+            q = 6089.5424232724435504633068+x*q;
+            q = 4958.82756472114071495438422+x*q;
+            q = 1826.3348842295112595576438+x*q;
+            result = Math.Exp(-AP.Math.Sqr(x))*p/q;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Normal distribution function
+
+        Returns the area under the Gaussian probability density
+        function, integrated from minus infinity to x:
+
+                                   x
+                                    -
+                          1        | |          2
+           ndtr(x)  = ---------    |    exp( - t /2 ) dt
+                      sqrt(2pi)  | |
+                                  -
+                                 -inf.
+
+                    =  ( 1 + erf(z) ) / 2
+                    =  erfc(z) / 2
+
+        where z = x/sqrt(2). Computation is via the functions
+        erf and erfc.
+
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE     -13,0        30000       3.4e-14     6.7e-15
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double normaldistribution(double x)
+        {
+            double result = 0;
+
+            result = 0.5*(erf(x/1.41421356237309504880)+1);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse of the error function
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double inverf(double e)
+        {
+            double result = 0;
+
+            result = invnormaldistribution(0.5*(e+1))/Math.Sqrt(2);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse of Normal distribution function
+
+        Returns the argument, x, for which the area under the
+        Gaussian probability density function (integrated from
+        minus infinity to x) is equal to y.
+
+
+        For small arguments 0 < y < exp(-2), the program computes
+        z = sqrt( -2.0 * log(y) );  then the approximation is
+        x = z - log(z)/z  - (1/z) P(1/z) / Q(1/z).
+        There are two rational functions P/Q, one for 0 < y < exp(-32)
+        and the other for y up to exp(-2).  For larger arguments,
+        w = y - 0.5, and  x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)).
+
+        ACCURACY:
+
+                             Relative error:
+        arithmetic   domain        # trials      peak         rms
+           IEEE     0.125, 1        20000       7.2e-16     1.3e-16
+           IEEE     3e-308, 0.135   50000       4.6e-16     9.8e-17
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invnormaldistribution(double y0)
+        {
+            double result = 0;
+            double expm2 = 0;
+            double s2pi = 0;
+            double x = 0;
+            double y = 0;
+            double z = 0;
+            double y2 = 0;
+            double x0 = 0;
+            double x1 = 0;
+            int code = 0;
+            double p0 = 0;
+            double q0 = 0;
+            double p1 = 0;
+            double q1 = 0;
+            double p2 = 0;
+            double q2 = 0;
+
+            expm2 = 0.13533528323661269189;
+            s2pi = 2.50662827463100050242;
+            if( (double)(y0)<=(double)(0) )
+            {
+                result = -AP.Math.MaxRealNumber;
+                return result;
+            }
+            if( (double)(y0)>=(double)(1) )
+            {
+                result = AP.Math.MaxRealNumber;
+                return result;
+            }
+            code = 1;
+            y = y0;
+            if( (double)(y)>(double)(1.0-expm2) )
+            {
+                y = 1.0-y;
+                code = 0;
+            }
+            if( (double)(y)>(double)(expm2) )
+            {
+                y = y-0.5;
+                y2 = y*y;
+                p0 = -59.9633501014107895267;
+                p0 = 98.0010754185999661536+y2*p0;
+                p0 = -56.6762857469070293439+y2*p0;
+                p0 = 13.9312609387279679503+y2*p0;
+                p0 = -1.23916583867381258016+y2*p0;
+                q0 = 1;
+                q0 = 1.95448858338141759834+y2*q0;
+                q0 = 4.67627912898881538453+y2*q0;
+                q0 = 86.3602421390890590575+y2*q0;
+                q0 = -225.462687854119370527+y2*q0;
+                q0 = 200.260212380060660359+y2*q0;
+                q0 = -82.0372256168333339912+y2*q0;
+                q0 = 15.9056225126211695515+y2*q0;
+                q0 = -1.18331621121330003142+y2*q0;
+                x = y+y*y2*p0/q0;
+                x = x*s2pi;
+                result = x;
+                return result;
+            }
+            x = Math.Sqrt(-(2.0*Math.Log(y)));
+            x0 = x-Math.Log(x)/x;
+            z = 1.0/x;
+            if( (double)(x)<(double)(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;
+            if( code!=0 )
+            {
+                x = -x;
+            }
+            result = x;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/nsevd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/nsevd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/nsevd.cs	(revision 2645)
@@ -0,0 +1,2100 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class nsevd
+    {
+        /*************************************************************************
+        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.
+        *************************************************************************/
+        public static bool rmatrixevd(double[,] a,
+            int n,
+            int vneeded,
+            ref double[] wr,
+            ref double[] wi,
+            ref double[,] vl,
+            ref double[,] vr)
+        {
+            bool result = new bool();
+            double[,] a1 = new double[0,0];
+            double[,] vl1 = new double[0,0];
+            double[,] vr1 = new double[0,0];
+            double[] wr1 = new double[0];
+            double[] wi1 = new double[0];
+            int i = 0;
+            double mx = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(vneeded>=0 & vneeded<=3, "RMatrixEVD: incorrect VNeeded!");
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = a[i-1,i_+i1_];
+                }
+            }
+            result = nonsymmetricevd(a1, n, vneeded, ref wr1, ref wi1, ref vl1, ref vr1);
+            if( result )
+            {
+                wr = new double[n-1+1];
+                wi = new double[n-1+1];
+                i1_ = (1) - (0);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    wr[i_] = wr1[i_+i1_];
+                }
+                i1_ = (1) - (0);
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    wi[i_] = wi1[i_+i1_];
+                }
+                if( vneeded==2 | vneeded==3 )
+                {
+                    vl = new double[n-1+1, n-1+1];
+                    for(i=0; i<=n-1; i++)
+                    {
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            vl[i,i_] = vl1[i+1,i_+i1_];
+                        }
+                    }
+                }
+                if( vneeded==1 | vneeded==3 )
+                {
+                    vr = new double[n-1+1, n-1+1];
+                    for(i=0; i<=n-1; i++)
+                    {
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            vr[i,i_] = vr1[i+1,i_+i1_];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool nonsymmetricevd(double[,] a,
+            int n,
+            int vneeded,
+            ref double[] wr,
+            ref double[] wi,
+            ref double[,] vl,
+            ref double[,] vr)
+        {
+            bool result = new bool();
+            double[,] s = new double[0,0];
+            double[] tau = new double[0];
+            bool[] sel = new bool[0];
+            int i = 0;
+            int info = 0;
+            int m = 0;
+            int i_ = 0;
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(vneeded>=0 & vneeded<=3, "NonSymmetricEVD: incorrect VNeeded!");
+            if( vneeded==0 )
+            {
+                
+                //
+                // Eigen values only
+                //
+                hessenberg.toupperhessenberg(ref a, n, ref tau);
+                hsschur.internalschurdecomposition(ref a, n, 0, 0, ref wr, ref wi, ref s, ref info);
+                result = info==0;
+                return result;
+            }
+            
+            //
+            // Eigen values and vectors
+            //
+            hessenberg.toupperhessenberg(ref a, n, ref tau);
+            hessenberg.unpackqfromupperhessenberg(ref a, n, ref tau, ref s);
+            hsschur.internalschurdecomposition(ref a, n, 1, 1, ref wr, ref wi, ref s, ref info);
+            result = info==0;
+            if( !result )
+            {
+                return result;
+            }
+            if( vneeded==1 | vneeded==3 )
+            {
+                vr = new double[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        vr[i,i_] = s[i,i_];
+                    }
+                }
+            }
+            if( vneeded==2 | vneeded==3 )
+            {
+                vl = new double[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        vl[i,i_] = s[i,i_];
+                    }
+                }
+            }
+            internaltrevc(ref a, n, vneeded, 1, sel, ref vl, ref vr, ref m, ref info);
+            result = info==0;
+            return result;
+        }
+
+
+        private static void internaltrevc(ref double[,] t,
+            int n,
+            int side,
+            int howmny,
+            bool[] vselect,
+            ref double[,] vl,
+            ref double[,] vr,
+            ref int m,
+            ref int info)
+        {
+            bool allv = new bool();
+            bool bothv = new bool();
+            bool leftv = new bool();
+            bool over = new bool();
+            bool pair = new bool();
+            bool rightv = new bool();
+            bool somev = new bool();
+            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;
+            double[,] x = new double[0,0];
+            double[] work = new double[0];
+            double[] temp = new double[0];
+            double[,] temp11 = new double[0,0];
+            double[,] temp22 = new double[0,0];
+            double[,] temp11b = new double[0,0];
+            double[,] temp21b = new double[0,0];
+            double[,] temp12b = new double[0,0];
+            double[,] temp22b = new double[0,0];
+            bool skipflag = new bool();
+            int k1 = 0;
+            int k2 = 0;
+            int k3 = 0;
+            int k4 = 0;
+            double vt = 0;
+            bool[] rswap4 = new bool[0];
+            bool[] zswap4 = new bool[0];
+            int[,] ipivot44 = new int[0,0];
+            double[] civ4 = new double[0];
+            double[] crv4 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            vselect = (bool[])vselect.Clone();
+
+            x = new double[2+1, 2+1];
+            temp11 = new double[1+1, 1+1];
+            temp11b = new double[1+1, 1+1];
+            temp21b = new double[2+1, 1+1];
+            temp12b = new double[1+1, 2+1];
+            temp22b = new double[2+1, 2+1];
+            temp22 = new double[2+1, 2+1];
+            work = new double[3*n+1];
+            temp = new double[n+1];
+            rswap4 = new bool[4+1];
+            zswap4 = new bool[4+1];
+            ipivot44 = new int[4+1, 4+1];
+            civ4 = new double[4+1];
+            crv4 = new double[4+1];
+            if( howmny!=1 )
+            {
+                if( side==1 | side==3 )
+                {
+                    vr = new double[n+1, n+1];
+                }
+                if( side==2 | side==3 )
+                {
+                    vl = new double[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;
+            if( n<0 )
+            {
+                info = -2;
+                return;
+            }
+            if( !rightv & !leftv )
+            {
+                info = -3;
+                return;
+            }
+            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++)
+                {
+                    if( pair )
+                    {
+                        pair = false;
+                        vselect[j] = false;
+                    }
+                    else
+                    {
+                        if( j<n )
+                        {
+                            if( (double)(t[j+1,j])==(double)(0) )
+                            {
+                                if( vselect[j] )
+                                {
+                                    m = m+1;
+                                }
+                            }
+                            else
+                            {
+                                pair = true;
+                                if( vselect[j] | vselect[j+1] )
+                                {
+                                    vselect[j] = true;
+                                    m = m+2;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            if( vselect[n] )
+                            {
+                                m = m+1;
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                m = n;
+            }
+            
+            //
+            // Quick return if possible.
+            //
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // Set the constants to control overflow.
+            //
+            unfl = AP.Math.MinRealNumber;
+            ovfl = 1/unfl;
+            ulp = AP.Math.MachineEpsilon;
+            smlnum = unfl*(n/ulp);
+            bignum = (1-ulp)/smlnum;
+            
+            //
+            // Compute 1-norm of each column of strictly upper triangular
+            // part of T to control overflow in triangular solver.
+            //
+            work[1] = 0;
+            for(j=2; j<=n; j++)
+            {
+                work[j] = 0;
+                for(i=1; i<=j-1; i++)
+                {
+                    work[j] = work[j]+Math.Abs(t[i,j]);
+                }
+            }
+            
+            //
+            // Index IP is used to specify the real or complex eigenvalue:
+            // IP = 0, real eigenvalue,
+            //      1, first of conjugate complex pair: (wr,wi)
+            //     -1, second of conjugate complex pair: (wr,wi)
+            //
+            n2 = 2*n;
+            if( rightv )
+            {
+                
+                //
+                // Compute right eigenvectors.
+                //
+                ip = 0;
+                iis = m;
+                for(ki=n; ki>=1; ki--)
+                {
+                    skipflag = false;
+                    if( ip==1 )
+                    {
+                        skipflag = true;
+                    }
+                    else
+                    {
+                        if( ki!=1 )
+                        {
+                            if( (double)(t[ki,ki-1])!=(double)(0) )
+                            {
+                                ip = -1;
+                            }
+                        }
+                        if( somev )
+                        {
+                            if( ip==0 )
+                            {
+                                if( !vselect[ki] )
+                                {
+                                    skipflag = true;
+                                }
+                            }
+                            else
+                            {
+                                if( !vselect[ki-1] )
+                                {
+                                    skipflag = true;
+                                }
+                            }
+                        }
+                    }
+                    if( !skipflag )
+                    {
+                        
+                        //
+                        // Compute the KI-th eigenvalue (WR,WI).
+                        //
+                        wr = t[ki,ki];
+                        wi = 0;
+                        if( ip!=0 )
+                        {
+                            wi = Math.Sqrt(Math.Abs(t[ki,ki-1]))*Math.Sqrt(Math.Abs(t[ki-1,ki]));
+                        }
+                        smin = Math.Max(ulp*(Math.Abs(wr)+Math.Abs(wi)), smlnum);
+                        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--)
+                            {
+                                if( j>jnxt )
+                                {
+                                    continue;
+                                }
+                                j1 = j;
+                                j2 = j;
+                                jnxt = j-1;
+                                if( j>1 )
+                                {
+                                    if( (double)(t[j,j-1])!=(double)(0) )
+                                    {
+                                        j1 = j-1;
+                                        jnxt = j-2;
+                                    }
+                                }
+                                if( j1==j2 )
+                                {
+                                    
+                                    //
+                                    // 1-by-1 diagonal block
+                                    //
+                                    temp11[1,1] = t[j,j];
+                                    temp11b[1,1] = work[j+n];
+                                    internalhsevdlaln2(false, 1, 1, smin, 1, ref temp11, 1.0, 1.0, ref temp11b, wr, 0.0, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale X(1,1) to avoid overflow when updating
+                                    // the right-hand side.
+                                    //
+                                    if( (double)(xnorm)>(double)(1) )
+                                    {
+                                        if( (double)(work[j])>(double)(bignum/xnorm) )
+                                        {
+                                            x[1,1] = x[1,1]/xnorm;
+                                            scl = scl/xnorm;
+                                        }
+                                    }
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        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,1] = t[j-1,j-1];
+                                    temp22[1,2] = t[j-1,j];
+                                    temp22[2,1] = t[j,j-1];
+                                    temp22[2,2] = t[j,j];
+                                    temp21b[1,1] = work[j-1+n];
+                                    temp21b[2,1] = work[j+n];
+                                    internalhsevdlaln2(false, 2, 1, smin, 1.0, ref temp22, 1.0, 1.0, ref temp21b, wr, 0, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale X(1,1) and X(2,1) to avoid overflow when
+                                    // updating the right-hand side.
+                                    //
+                                    if( (double)(xnorm)>(double)(1) )
+                                    {
+                                        beta = Math.Max(work[j-1], work[j]);
+                                        if( (double)(beta)>(double)(bignum/xnorm) )
+                                        {
+                                            x[1,1] = x[1,1]/xnorm;
+                                            x[2,1] = x[2,1]/xnorm;
+                                            scl = scl/xnorm;
+                                        }
+                                    }
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        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_,iis] = work[i_+i1_];
+                                }
+                                ii = blas.columnidxabsmax(ref vr, 1, ki, iis);
+                                remax = 1/Math.Abs(vr[ii,iis]);
+                                for(i_=1; i_<=ki;i_++)
+                                {
+                                    vr[i_,iis] = remax*vr[i_,iis];
+                                }
+                                for(k=ki+1; k<=n; k++)
+                                {
+                                    vr[k,iis] = 0;
+                                }
+                            }
+                            else
+                            {
+                                if( ki>1 )
+                                {
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        temp[i_] = vr[i_,ki];
+                                    }
+                                    blas.matrixvectormultiply(ref vr, 1, n, 1, ki-1, false, ref work, 1+n, ki-1+n, 1.0, ref temp, 1, n, work[ki+n]);
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vr[i_,ki] = temp[i_];
+                                    }
+                                }
+                                ii = blas.columnidxabsmax(ref vr, 1, n, ki);
+                                remax = 1/Math.Abs(vr[ii,ki]);
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    vr[i_,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( (double)(Math.Abs(t[ki-1,ki]))>=(double)(Math.Abs(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--)
+                            {
+                                if( j>jnxt )
+                                {
+                                    continue;
+                                }
+                                j1 = j;
+                                j2 = j;
+                                jnxt = j-1;
+                                if( j>1 )
+                                {
+                                    if( (double)(t[j,j-1])!=(double)(0) )
+                                    {
+                                        j1 = j-1;
+                                        jnxt = j-2;
+                                    }
+                                }
+                                if( j1==j2 )
+                                {
+                                    
+                                    //
+                                    // 1-by-1 diagonal block
+                                    //
+                                    temp11[1,1] = t[j,j];
+                                    temp12b[1,1] = work[j+n];
+                                    temp12b[1,2] = work[j+n+n];
+                                    internalhsevdlaln2(false, 1, 2, smin, 1.0, ref temp11, 1.0, 1.0, ref temp12b, wr, wi, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale X(1,1) and X(1,2) to avoid overflow when
+                                    // updating the right-hand side.
+                                    //
+                                    if( (double)(xnorm)>(double)(1) )
+                                    {
+                                        if( (double)(work[j])>(double)(bignum/xnorm) )
+                                        {
+                                            x[1,1] = x[1,1]/xnorm;
+                                            x[1,2] = x[1,2]/xnorm;
+                                            scl = scl/xnorm;
+                                        }
+                                    }
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        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];
+                                    }
+                                    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,1] = t[j-1,j-1];
+                                    temp22[1,2] = t[j-1,j];
+                                    temp22[2,1] = t[j,j-1];
+                                    temp22[2,2] = t[j,j];
+                                    temp22b[1,1] = work[j-1+n];
+                                    temp22b[1,2] = work[j-1+n+n];
+                                    temp22b[2,1] = work[j+n];
+                                    temp22b[2,2] = work[j+n+n];
+                                    internalhsevdlaln2(false, 2, 2, smin, 1.0, ref temp22, 1.0, 1.0, ref temp22b, wr, wi, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale X to avoid overflow when updating
+                                    // the right-hand side.
+                                    //
+                                    if( (double)(xnorm)>(double)(1) )
+                                    {
+                                        beta = Math.Max(work[j-1], work[j]);
+                                        if( (double)(beta)>(double)(bignum/xnorm) )
+                                        {
+                                            rec = 1/xnorm;
+                                            x[1,1] = x[1,1]*rec;
+                                            x[1,2] = x[1,2]*rec;
+                                            x[2,1] = x[2,1]*rec;
+                                            x[2,2] = x[2,2]*rec;
+                                            scl = scl*rec;
+                                        }
+                                    }
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        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_];
+                                        }
+                                    }
+                                    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_ = (1) - (n+1);
+                                    for(i_=n+1; i_<=n+j-2;i_++)
+                                    {
+                                        work[i_] = work[i_] + vt*t[i_+i1_,j-1];
+                                    }
+                                    vt = -x[2,1];
+                                    i1_ = (1) - (n+1);
+                                    for(i_=n+1; i_<=n+j-2;i_++)
+                                    {
+                                        work[i_] = work[i_] + vt*t[i_+i1_,j];
+                                    }
+                                    vt = -x[1,2];
+                                    i1_ = (1) - (n2+1);
+                                    for(i_=n2+1; i_<=n2+j-2;i_++)
+                                    {
+                                        work[i_] = work[i_] + vt*t[i_+i1_,j-1];
+                                    }
+                                    vt = -x[2,2];
+                                    i1_ = (1) - (n2+1);
+                                    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+1) - (1);
+                                for(i_=1; i_<=ki;i_++)
+                                {
+                                    vr[i_,iis-1] = work[i_+i1_];
+                                }
+                                i1_ = (n2+1) - (1);
+                                for(i_=1; i_<=ki;i_++)
+                                {
+                                    vr[i_,iis] = work[i_+i1_];
+                                }
+                                emax = 0;
+                                for(k=1; k<=ki; k++)
+                                {
+                                    emax = Math.Max(emax, Math.Abs(vr[k,iis-1])+Math.Abs(vr[k,iis]));
+                                }
+                                remax = 1/emax;
+                                for(i_=1; i_<=ki;i_++)
+                                {
+                                    vr[i_,iis-1] = remax*vr[i_,iis-1];
+                                }
+                                for(i_=1; i_<=ki;i_++)
+                                {
+                                    vr[i_,iis] = remax*vr[i_,iis];
+                                }
+                                for(k=ki+1; k<=n; k++)
+                                {
+                                    vr[k,iis-1] = 0;
+                                    vr[k,iis] = 0;
+                                }
+                            }
+                            else
+                            {
+                                if( ki>2 )
+                                {
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        temp[i_] = vr[i_,ki-1];
+                                    }
+                                    blas.matrixvectormultiply(ref vr, 1, n, 1, ki-2, false, ref work, 1+n, ki-2+n, 1.0, ref temp, 1, n, work[ki-1+n]);
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vr[i_,ki-1] = temp[i_];
+                                    }
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        temp[i_] = vr[i_,ki];
+                                    }
+                                    blas.matrixvectormultiply(ref vr, 1, n, 1, ki-2, false, ref work, 1+n2, ki-2+n2, 1.0, ref temp, 1, n, work[ki+n2]);
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vr[i_,ki] = temp[i_];
+                                    }
+                                }
+                                else
+                                {
+                                    vt = work[ki-1+n];
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vr[i_,ki-1] = vt*vr[i_,ki-1];
+                                    }
+                                    vt = work[ki+n2];
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vr[i_,ki] = vt*vr[i_,ki];
+                                    }
+                                }
+                                emax = 0;
+                                for(k=1; k<=n; k++)
+                                {
+                                    emax = Math.Max(emax, Math.Abs(vr[k,ki-1])+Math.Abs(vr[k,ki]));
+                                }
+                                remax = 1/emax;
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    vr[i_,ki-1] = remax*vr[i_,ki-1];
+                                }
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    vr[i_,ki] = remax*vr[i_,ki];
+                                }
+                            }
+                        }
+                        iis = iis-1;
+                        if( ip!=0 )
+                        {
+                            iis = iis-1;
+                        }
+                    }
+                    if( ip==1 )
+                    {
+                        ip = 0;
+                    }
+                    if( ip==-1 )
+                    {
+                        ip = 1;
+                    }
+                }
+            }
+            if( leftv )
+            {
+                
+                //
+                // Compute left eigenvectors.
+                //
+                ip = 0;
+                iis = 1;
+                for(ki=1; ki<=n; ki++)
+                {
+                    skipflag = false;
+                    if( ip==-1 )
+                    {
+                        skipflag = true;
+                    }
+                    else
+                    {
+                        if( ki!=n )
+                        {
+                            if( (double)(t[ki+1,ki])!=(double)(0) )
+                            {
+                                ip = 1;
+                            }
+                        }
+                        if( somev )
+                        {
+                            if( !vselect[ki] )
+                            {
+                                skipflag = true;
+                            }
+                        }
+                    }
+                    if( !skipflag )
+                    {
+                        
+                        //
+                        // Compute the KI-th eigenvalue (WR,WI).
+                        //
+                        wr = t[ki,ki];
+                        wi = 0;
+                        if( ip!=0 )
+                        {
+                            wi = Math.Sqrt(Math.Abs(t[ki,ki+1]))*Math.Sqrt(Math.Abs(t[ki+1,ki]));
+                        }
+                        smin = Math.Max(ulp*(Math.Abs(wr)+Math.Abs(wi)), smlnum);
+                        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++)
+                            {
+                                if( j<jnxt )
+                                {
+                                    continue;
+                                }
+                                j1 = j;
+                                j2 = j;
+                                jnxt = j+1;
+                                if( j<n )
+                                {
+                                    if( (double)(t[j+1,j])!=(double)(0) )
+                                    {
+                                        j2 = j+1;
+                                        jnxt = j+2;
+                                    }
+                                }
+                                if( j1==j2 )
+                                {
+                                    
+                                    //
+                                    // 1-by-1 diagonal block
+                                    //
+                                    // Scale if necessary to avoid overflow when forming
+                                    // the right-hand side.
+                                    //
+                                    if( (double)(work[j])>(double)(vcrit) )
+                                    {
+                                        rec = 1/vmax;
+                                        for(i_=ki+n; i_<=n+n;i_++)
+                                        {
+                                            work[i_] = rec*work[i_];
+                                        }
+                                        vmax = 1;
+                                        vcrit = bignum;
+                                    }
+                                    i1_ = (ki+1+n)-(ki+1);
+                                    vt = 0.0;
+                                    for(i_=ki+1; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j]*work[i_+i1_];
+                                    }
+                                    work[j+n] = work[j+n]-vt;
+                                    
+                                    //
+                                    // Solve (T(J,J)-WR)'*X = WORK
+                                    //
+                                    temp11[1,1] = t[j,j];
+                                    temp11b[1,1] = work[j+n];
+                                    internalhsevdlaln2(false, 1, 1, smin, 1.0, ref temp11, 1.0, 1.0, ref temp11b, wr, 0, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        for(i_=ki+n; i_<=n+n;i_++)
+                                        {
+                                            work[i_] = scl*work[i_];
+                                        }
+                                    }
+                                    work[j+n] = x[1,1];
+                                    vmax = Math.Max(Math.Abs(work[j+n]), vmax);
+                                    vcrit = bignum/vmax;
+                                }
+                                else
+                                {
+                                    
+                                    //
+                                    // 2-by-2 diagonal block
+                                    //
+                                    // Scale if necessary to avoid overflow when forming
+                                    // the right-hand side.
+                                    //
+                                    beta = Math.Max(work[j], work[j+1]);
+                                    if( (double)(beta)>(double)(vcrit) )
+                                    {
+                                        rec = 1/vmax;
+                                        for(i_=ki+n; i_<=n+n;i_++)
+                                        {
+                                            work[i_] = rec*work[i_];
+                                        }
+                                        vmax = 1;
+                                        vcrit = bignum;
+                                    }
+                                    i1_ = (ki+1+n)-(ki+1);
+                                    vt = 0.0;
+                                    for(i_=ki+1; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j]*work[i_+i1_];
+                                    }
+                                    work[j+n] = work[j+n]-vt;
+                                    i1_ = (ki+1+n)-(ki+1);
+                                    vt = 0.0;
+                                    for(i_=ki+1; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j+1]*work[i_+i1_];
+                                    }
+                                    work[j+1+n] = work[j+1+n]-vt;
+                                    
+                                    //
+                                    // Solve
+                                    //    [T(J,J)-WR   T(J,J+1)     ]'* X = SCALE*( WORK1 )
+                                    //    [T(J+1,J)    T(J+1,J+1)-WR]             ( WORK2 )
+                                    //
+                                    temp22[1,1] = t[j,j];
+                                    temp22[1,2] = t[j,j+1];
+                                    temp22[2,1] = t[j+1,j];
+                                    temp22[2,2] = t[j+1,j+1];
+                                    temp21b[1,1] = work[j+n];
+                                    temp21b[2,1] = work[j+1+n];
+                                    internalhsevdlaln2(true, 2, 1, smin, 1.0, ref temp22, 1.0, 1.0, ref temp21b, wr, 0, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        for(i_=ki+n; i_<=n+n;i_++)
+                                        {
+                                            work[i_] = scl*work[i_];
+                                        }
+                                    }
+                                    work[j+n] = x[1,1];
+                                    work[j+1+n] = x[2,1];
+                                    vmax = Math.Max(Math.Abs(work[j+n]), Math.Max(Math.Abs(work[j+1+n]), vmax));
+                                    vcrit = bignum/vmax;
+                                }
+                            }
+                            
+                            //
+                            // Copy the vector x or Q*x to VL and normalize.
+                            //
+                            if( !over )
+                            {
+                                i1_ = (ki+n) - (ki);
+                                for(i_=ki; i_<=n;i_++)
+                                {
+                                    vl[i_,iis] = work[i_+i1_];
+                                }
+                                ii = blas.columnidxabsmax(ref vl, ki, n, iis);
+                                remax = 1/Math.Abs(vl[ii,iis]);
+                                for(i_=ki; i_<=n;i_++)
+                                {
+                                    vl[i_,iis] = remax*vl[i_,iis];
+                                }
+                                for(k=1; k<=ki-1; k++)
+                                {
+                                    vl[k,iis] = 0;
+                                }
+                            }
+                            else
+                            {
+                                if( ki<n )
+                                {
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        temp[i_] = vl[i_,ki];
+                                    }
+                                    blas.matrixvectormultiply(ref vl, 1, n, ki+1, n, false, ref work, ki+1+n, n+n, 1.0, ref temp, 1, n, work[ki+n]);
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vl[i_,ki] = temp[i_];
+                                    }
+                                }
+                                ii = blas.columnidxabsmax(ref vl, 1, n, ki);
+                                remax = 1/Math.Abs(vl[ii,ki]);
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    vl[i_,ki] = remax*vl[i_,ki];
+                                }
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // Complex left eigenvector.
+                            //
+                            // Initial solve:
+                            //   ((T(KI,KI)    T(KI,KI+1) )' - (WR - I* WI))*X = 0.
+                            //   ((T(KI+1,KI) T(KI+1,KI+1))                )
+                            //
+                            if( (double)(Math.Abs(t[ki,ki+1]))>=(double)(Math.Abs(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++)
+                            {
+                                if( j<jnxt )
+                                {
+                                    continue;
+                                }
+                                j1 = j;
+                                j2 = j;
+                                jnxt = j+1;
+                                if( j<n )
+                                {
+                                    if( (double)(t[j+1,j])!=(double)(0) )
+                                    {
+                                        j2 = j+1;
+                                        jnxt = j+2;
+                                    }
+                                }
+                                if( j1==j2 )
+                                {
+                                    
+                                    //
+                                    // 1-by-1 diagonal block
+                                    //
+                                    // Scale if necessary to avoid overflow when
+                                    // forming the right-hand side elements.
+                                    //
+                                    if( (double)(work[j])>(double)(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_ = (ki+2+n)-(ki+2);
+                                    vt = 0.0;
+                                    for(i_=ki+2; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j]*work[i_+i1_];
+                                    }
+                                    work[j+n] = work[j+n]-vt;
+                                    i1_ = (ki+2+n2)-(ki+2);
+                                    vt = 0.0;
+                                    for(i_=ki+2; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j]*work[i_+i1_];
+                                    }
+                                    work[j+n2] = work[j+n2]-vt;
+                                    
+                                    //
+                                    // Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2
+                                    //
+                                    temp11[1,1] = t[j,j];
+                                    temp12b[1,1] = work[j+n];
+                                    temp12b[1,2] = work[j+n+n];
+                                    internalhsevdlaln2(false, 1, 2, smin, 1.0, ref temp11, 1.0, 1.0, ref temp12b, wr, -wi, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        for(i_=ki+n; i_<=n+n;i_++)
+                                        {
+                                            work[i_] = scl*work[i_];
+                                        }
+                                        for(i_=ki+n2; i_<=n+n2;i_++)
+                                        {
+                                            work[i_] = scl*work[i_];
+                                        }
+                                    }
+                                    work[j+n] = x[1,1];
+                                    work[j+n2] = x[1,2];
+                                    vmax = Math.Max(Math.Abs(work[j+n]), Math.Max(Math.Abs(work[j+n2]), vmax));
+                                    vcrit = bignum/vmax;
+                                }
+                                else
+                                {
+                                    
+                                    //
+                                    // 2-by-2 diagonal block
+                                    //
+                                    // Scale if necessary to avoid overflow when forming
+                                    // the right-hand side elements.
+                                    //
+                                    beta = Math.Max(work[j], work[j+1]);
+                                    if( (double)(beta)>(double)(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_ = (ki+2+n)-(ki+2);
+                                    vt = 0.0;
+                                    for(i_=ki+2; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j]*work[i_+i1_];
+                                    }
+                                    work[j+n] = work[j+n]-vt;
+                                    i1_ = (ki+2+n2)-(ki+2);
+                                    vt = 0.0;
+                                    for(i_=ki+2; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j]*work[i_+i1_];
+                                    }
+                                    work[j+n2] = work[j+n2]-vt;
+                                    i1_ = (ki+2+n)-(ki+2);
+                                    vt = 0.0;
+                                    for(i_=ki+2; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j+1]*work[i_+i1_];
+                                    }
+                                    work[j+1+n] = work[j+1+n]-vt;
+                                    i1_ = (ki+2+n2)-(ki+2);
+                                    vt = 0.0;
+                                    for(i_=ki+2; i_<=j-1;i_++)
+                                    {
+                                        vt += t[i_,j+1]*work[i_+i1_];
+                                    }
+                                    work[j+1+n2] = work[j+1+n2]-vt;
+                                    
+                                    //
+                                    // Solve 2-by-2 complex linear equation
+                                    //   ([T(j,j)   T(j,j+1)  ]'-(wr-i*wi)*I)*X = SCALE*B
+                                    //   ([T(j+1,j) T(j+1,j+1)]             )
+                                    //
+                                    temp22[1,1] = t[j,j];
+                                    temp22[1,2] = t[j,j+1];
+                                    temp22[2,1] = t[j+1,j];
+                                    temp22[2,2] = t[j+1,j+1];
+                                    temp22b[1,1] = work[j+n];
+                                    temp22b[1,2] = work[j+n+n];
+                                    temp22b[2,1] = work[j+1+n];
+                                    temp22b[2,2] = work[j+1+n+n];
+                                    internalhsevdlaln2(true, 2, 2, smin, 1.0, ref temp22, 1.0, 1.0, ref temp22b, wr, -wi, ref rswap4, ref zswap4, ref ipivot44, ref civ4, ref crv4, ref x, ref scl, ref xnorm, ref ierr);
+                                    
+                                    //
+                                    // Scale if necessary
+                                    //
+                                    if( (double)(scl)!=(double)(1) )
+                                    {
+                                        for(i_=ki+n; i_<=n+n;i_++)
+                                        {
+                                            work[i_] = scl*work[i_];
+                                        }
+                                        for(i_=ki+n2; i_<=n+n2;i_++)
+                                        {
+                                            work[i_] = scl*work[i_];
+                                        }
+                                    }
+                                    work[j+n] = x[1,1];
+                                    work[j+n2] = x[1,2];
+                                    work[j+1+n] = x[2,1];
+                                    work[j+1+n2] = x[2,2];
+                                    vmax = Math.Max(Math.Abs(x[1,1]), vmax);
+                                    vmax = Math.Max(Math.Abs(x[1,2]), vmax);
+                                    vmax = Math.Max(Math.Abs(x[2,1]), vmax);
+                                    vmax = Math.Max(Math.Abs(x[2,2]), vmax);
+                                    vcrit = bignum/vmax;
+                                }
+                            }
+                            
+                            //
+                            // Copy the vector x or Q*x to VL and normalize.
+                            //
+                            if( !over )
+                            {
+                                i1_ = (ki+n) - (ki);
+                                for(i_=ki; i_<=n;i_++)
+                                {
+                                    vl[i_,iis] = work[i_+i1_];
+                                }
+                                i1_ = (ki+n2) - (ki);
+                                for(i_=ki; i_<=n;i_++)
+                                {
+                                    vl[i_,iis+1] = work[i_+i1_];
+                                }
+                                emax = 0;
+                                for(k=ki; k<=n; k++)
+                                {
+                                    emax = Math.Max(emax, Math.Abs(vl[k,iis])+Math.Abs(vl[k,iis+1]));
+                                }
+                                remax = 1/emax;
+                                for(i_=ki; i_<=n;i_++)
+                                {
+                                    vl[i_,iis] = remax*vl[i_,iis];
+                                }
+                                for(i_=ki; i_<=n;i_++)
+                                {
+                                    vl[i_,iis+1] = remax*vl[i_,iis+1];
+                                }
+                                for(k=1; k<=ki-1; k++)
+                                {
+                                    vl[k,iis] = 0;
+                                    vl[k,iis+1] = 0;
+                                }
+                            }
+                            else
+                            {
+                                if( ki<n-1 )
+                                {
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        temp[i_] = vl[i_,ki];
+                                    }
+                                    blas.matrixvectormultiply(ref vl, 1, n, ki+2, n, false, ref work, ki+2+n, n+n, 1.0, ref temp, 1, n, work[ki+n]);
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vl[i_,ki] = temp[i_];
+                                    }
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        temp[i_] = vl[i_,ki+1];
+                                    }
+                                    blas.matrixvectormultiply(ref vl, 1, n, ki+2, n, false, ref work, ki+2+n2, n+n2, 1.0, ref temp, 1, n, work[ki+1+n2]);
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vl[i_,ki+1] = temp[i_];
+                                    }
+                                }
+                                else
+                                {
+                                    vt = work[ki+n];
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vl[i_,ki] = vt*vl[i_,ki];
+                                    }
+                                    vt = work[ki+1+n2];
+                                    for(i_=1; i_<=n;i_++)
+                                    {
+                                        vl[i_,ki+1] = vt*vl[i_,ki+1];
+                                    }
+                                }
+                                emax = 0;
+                                for(k=1; k<=n; k++)
+                                {
+                                    emax = Math.Max(emax, Math.Abs(vl[k,ki])+Math.Abs(vl[k,ki+1]));
+                                }
+                                remax = 1/emax;
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    vl[i_,ki] = remax*vl[i_,ki];
+                                }
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    vl[i_,ki+1] = remax*vl[i_,ki+1];
+                                }
+                            }
+                        }
+                        iis = iis+1;
+                        if( ip!=0 )
+                        {
+                            iis = iis+1;
+                        }
+                    }
+                    if( ip==-1 )
+                    {
+                        ip = 0;
+                    }
+                    if( ip==1 )
+                    {
+                        ip = -1;
+                    }
+                }
+            }
+        }
+
+
+        private static void internalhsevdlaln2(bool ltrans,
+            int na,
+            int nw,
+            double smin,
+            double ca,
+            ref double[,] a,
+            double d1,
+            double d2,
+            ref double[,] b,
+            double wr,
+            double wi,
+            ref bool[] rswap4,
+            ref bool[] zswap4,
+            ref int[,] ipivot44,
+            ref double[] civ4,
+            ref double[] crv4,
+            ref double[,] x,
+            ref double scl,
+            ref double xnorm,
+            ref int info)
+        {
+            int icmax = 0;
+            int j = 0;
+            double bbnd = 0;
+            double bi1 = 0;
+            double bi2 = 0;
+            double bignum = 0;
+            double bnorm = 0;
+            double br1 = 0;
+            double br2 = 0;
+            double ci21 = 0;
+            double ci22 = 0;
+            double cmax = 0;
+            double cnorm = 0;
+            double cr21 = 0;
+            double cr22 = 0;
+            double csi = 0;
+            double csr = 0;
+            double li21 = 0;
+            double lr21 = 0;
+            double smini = 0;
+            double smlnum = 0;
+            double temp = 0;
+            double u22abs = 0;
+            double ui11 = 0;
+            double ui11r = 0;
+            double ui12 = 0;
+            double ui12s = 0;
+            double ui22 = 0;
+            double ur11 = 0;
+            double ur11r = 0;
+            double ur12 = 0;
+            double ur12s = 0;
+            double ur22 = 0;
+            double xi1 = 0;
+            double xi2 = 0;
+            double xr1 = 0;
+            double xr2 = 0;
+            double tmp1 = 0;
+            double tmp2 = 0;
+
+            zswap4[1] = false;
+            zswap4[2] = false;
+            zswap4[3] = true;
+            zswap4[4] = true;
+            rswap4[1] = false;
+            rswap4[2] = true;
+            rswap4[3] = false;
+            rswap4[4] = true;
+            ipivot44[1,1] = 1;
+            ipivot44[2,1] = 2;
+            ipivot44[3,1] = 3;
+            ipivot44[4,1] = 4;
+            ipivot44[1,2] = 2;
+            ipivot44[2,2] = 1;
+            ipivot44[3,2] = 4;
+            ipivot44[4,2] = 3;
+            ipivot44[1,3] = 3;
+            ipivot44[2,3] = 4;
+            ipivot44[3,3] = 1;
+            ipivot44[4,3] = 2;
+            ipivot44[1,4] = 4;
+            ipivot44[2,4] = 3;
+            ipivot44[3,4] = 2;
+            ipivot44[4,4] = 1;
+            smlnum = 2*AP.Math.MinRealNumber;
+            bignum = 1/smlnum;
+            smini = Math.Max(smin, smlnum);
+            
+            //
+            // Don't check for input errors
+            //
+            info = 0;
+            
+            //
+            // Standard Initializations
+            //
+            scl = 1;
+            if( na==1 )
+            {
+                
+                //
+                // 1 x 1  (i.e., scalar) system   C X = B
+                //
+                if( nw==1 )
+                {
+                    
+                    //
+                    // Real 1x1 system.
+                    //
+                    // C = ca A - w D
+                    //
+                    csr = ca*a[1,1]-wr*d1;
+                    cnorm = Math.Abs(csr);
+                    
+                    //
+                    // If | C | < SMINI, use C = SMINI
+                    //
+                    if( (double)(cnorm)<(double)(smini) )
+                    {
+                        csr = smini;
+                        cnorm = smini;
+                        info = 1;
+                    }
+                    
+                    //
+                    // Check scaling for  X = B / C
+                    //
+                    bnorm = Math.Abs(b[1,1]);
+                    if( (double)(cnorm)<(double)(1) & (double)(bnorm)>(double)(1) )
+                    {
+                        if( (double)(bnorm)>(double)(bignum*cnorm) )
+                        {
+                            scl = 1/bnorm;
+                        }
+                    }
+                    
+                    //
+                    // Compute X
+                    //
+                    x[1,1] = b[1,1]*scl/csr;
+                    xnorm = Math.Abs(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 = Math.Abs(csr)+Math.Abs(csi);
+                    
+                    //
+                    // If | C | < SMINI, use C = SMINI
+                    //
+                    if( (double)(cnorm)<(double)(smini) )
+                    {
+                        csr = smini;
+                        csi = 0;
+                        cnorm = smini;
+                        info = 1;
+                    }
+                    
+                    //
+                    // Check scaling for  X = B / C
+                    //
+                    bnorm = Math.Abs(b[1,1])+Math.Abs(b[1,2]);
+                    if( (double)(cnorm)<(double)(1) & (double)(bnorm)>(double)(1) )
+                    {
+                        if( (double)(bnorm)>(double)(bignum*cnorm) )
+                        {
+                            scl = 1/bnorm;
+                        }
+                    }
+                    
+                    //
+                    // Compute X
+                    //
+                    internalhsevdladiv(scl*b[1,1], scl*b[1,2], csr, csi, ref tmp1, ref tmp2);
+                    x[1,1] = tmp1;
+                    x[1,2] = tmp2;
+                    xnorm = Math.Abs(x[1,1])+Math.Abs(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;
+                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];
+                }
+                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++)
+                    {
+                        if( (double)(Math.Abs(crv4[j]))>(double)(cmax) )
+                        {
+                            cmax = Math.Abs(crv4[j]);
+                            icmax = j;
+                        }
+                    }
+                    
+                    //
+                    // If norm(C) < SMINI, use SMINI*identity.
+                    //
+                    if( (double)(cmax)<(double)(smini) )
+                    {
+                        bnorm = Math.Max(Math.Abs(b[1,1]), Math.Abs(b[2,1]));
+                        if( (double)(smini)<(double)(1) & (double)(bnorm)>(double)(1) )
+                        {
+                            if( (double)(bnorm)>(double)(bignum*smini) )
+                            {
+                                scl = 1/bnorm;
+                            }
+                        }
+                        temp = scl/smini;
+                        x[1,1] = temp*b[1,1];
+                        x[2,1] = temp*b[2,1];
+                        xnorm = temp*bnorm;
+                        info = 1;
+                        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( (double)(Math.Abs(ur22))<(double)(smini) )
+                    {
+                        ur22 = smini;
+                        info = 1;
+                    }
+                    if( rswap4[icmax] )
+                    {
+                        br1 = b[2,1];
+                        br2 = b[1,1];
+                    }
+                    else
+                    {
+                        br1 = b[1,1];
+                        br2 = b[2,1];
+                    }
+                    br2 = br2-lr21*br1;
+                    bbnd = Math.Max(Math.Abs(br1*(ur22*ur11r)), Math.Abs(br2));
+                    if( (double)(bbnd)>(double)(1) & (double)(Math.Abs(ur22))<(double)(1) )
+                    {
+                        if( (double)(bbnd)>=(double)(bignum*Math.Abs(ur22)) )
+                        {
+                            scl = 1/bbnd;
+                        }
+                    }
+                    xr2 = br2*scl/ur22;
+                    xr1 = scl*br1*ur11r-xr2*(ur11r*ur12);
+                    if( zswap4[icmax] )
+                    {
+                        x[1,1] = xr2;
+                        x[2,1] = xr1;
+                    }
+                    else
+                    {
+                        x[1,1] = xr1;
+                        x[2,1] = xr2;
+                    }
+                    xnorm = Math.Max(Math.Abs(xr1), Math.Abs(xr2));
+                    
+                    //
+                    // Further scaling if  norm(A) norm(X) > overflow
+                    //
+                    if( (double)(xnorm)>(double)(1) & (double)(cmax)>(double)(1) )
+                    {
+                        if( (double)(xnorm)>(double)(bignum/cmax) )
+                        {
+                            temp = cmax/bignum;
+                            x[1,1] = temp*x[1,1];
+                            x[2,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++)
+                    {
+                        if( (double)(Math.Abs(crv4[j])+Math.Abs(civ4[j]))>(double)(cmax) )
+                        {
+                            cmax = Math.Abs(crv4[j])+Math.Abs(civ4[j]);
+                            icmax = j;
+                        }
+                    }
+                    
+                    //
+                    // If norm(C) < SMINI, use SMINI*identity.
+                    //
+                    if( (double)(cmax)<(double)(smini) )
+                    {
+                        bnorm = Math.Max(Math.Abs(b[1,1])+Math.Abs(b[1,2]), Math.Abs(b[2,1])+Math.Abs(b[2,2]));
+                        if( (double)(smini)<(double)(1) & (double)(bnorm)>(double)(1) )
+                        {
+                            if( (double)(bnorm)>(double)(bignum*smini) )
+                            {
+                                scl = 1/bnorm;
+                            }
+                        }
+                        temp = scl/smini;
+                        x[1,1] = temp*b[1,1];
+                        x[2,1] = temp*b[2,1];
+                        x[1,2] = temp*b[1,2];
+                        x[2,2] = temp*b[2,2];
+                        xnorm = temp*bnorm;
+                        info = 1;
+                        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]];
+                    if( icmax==1 | icmax==4 )
+                    {
+                        
+                        //
+                        // Code when off-diagonals of pivoted C are real
+                        //
+                        if( (double)(Math.Abs(ur11))>(double)(Math.Abs(ui11)) )
+                        {
+                            temp = ui11/ur11;
+                            ur11r = 1/(ur11*(1+AP.Math.Sqr(temp)));
+                            ui11r = -(temp*ur11r);
+                        }
+                        else
+                        {
+                            temp = ur11/ui11;
+                            ui11r = -(1/(ui11*(1+AP.Math.Sqr(temp))));
+                            ur11r = -(temp*ui11r);
+                        }
+                        lr21 = cr21*ur11r;
+                        li21 = cr21*ui11r;
+                        ur12s = ur12*ur11r;
+                        ui12s = ur12*ui11r;
+                        ur22 = cr22-ur12*lr21;
+                        ui22 = ci22-ur12*li21;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Code when diagonals of pivoted C are real
+                        //
+                        ur11r = 1/ur11;
+                        ui11r = 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 = Math.Abs(ur22)+Math.Abs(ui22);
+                    
+                    //
+                    // If smaller pivot < SMINI, use SMINI
+                    //
+                    if( (double)(u22abs)<(double)(smini) )
+                    {
+                        ur22 = smini;
+                        ui22 = 0;
+                        info = 1;
+                    }
+                    if( rswap4[icmax] )
+                    {
+                        br2 = b[1,1];
+                        br1 = b[2,1];
+                        bi2 = b[1,2];
+                        bi1 = b[2,2];
+                    }
+                    else
+                    {
+                        br1 = b[1,1];
+                        br2 = b[2,1];
+                        bi1 = b[1,2];
+                        bi2 = b[2,2];
+                    }
+                    br2 = br2-lr21*br1+li21*bi1;
+                    bi2 = bi2-li21*br1-lr21*bi1;
+                    bbnd = Math.Max((Math.Abs(br1)+Math.Abs(bi1))*(u22abs*(Math.Abs(ur11r)+Math.Abs(ui11r))), Math.Abs(br2)+Math.Abs(bi2));
+                    if( (double)(bbnd)>(double)(1) & (double)(u22abs)<(double)(1) )
+                    {
+                        if( (double)(bbnd)>=(double)(bignum*u22abs) )
+                        {
+                            scl = 1/bbnd;
+                            br1 = scl*br1;
+                            bi1 = scl*bi1;
+                            br2 = scl*br2;
+                            bi2 = scl*bi2;
+                        }
+                    }
+                    internalhsevdladiv(br2, bi2, ur22, ui22, ref xr2, ref xi2);
+                    xr1 = ur11r*br1-ui11r*bi1-ur12s*xr2+ui12s*xi2;
+                    xi1 = ui11r*br1+ur11r*bi1-ui12s*xr2-ur12s*xi2;
+                    if( zswap4[icmax] )
+                    {
+                        x[1,1] = xr2;
+                        x[2,1] = xr1;
+                        x[1,2] = xi2;
+                        x[2,2] = xi1;
+                    }
+                    else
+                    {
+                        x[1,1] = xr1;
+                        x[2,1] = xr2;
+                        x[1,2] = xi1;
+                        x[2,2] = xi2;
+                    }
+                    xnorm = Math.Max(Math.Abs(xr1)+Math.Abs(xi1), Math.Abs(xr2)+Math.Abs(xi2));
+                    
+                    //
+                    // Further scaling if  norm(A) norm(X) > overflow
+                    //
+                    if( (double)(xnorm)>(double)(1) & (double)(cmax)>(double)(1) )
+                    {
+                        if( (double)(xnorm)>(double)(bignum/cmax) )
+                        {
+                            temp = cmax/bignum;
+                            x[1,1] = temp*x[1,1];
+                            x[2,1] = temp*x[2,1];
+                            x[1,2] = temp*x[1,2];
+                            x[2,2] = temp*x[2,2];
+                            xnorm = temp*xnorm;
+                            scl = temp*scl;
+                        }
+                    }
+                }
+            }
+        }
+
+
+        private static void internalhsevdladiv(double a,
+            double b,
+            double c,
+            double d,
+            ref double p,
+            ref double q)
+        {
+            double e = 0;
+            double f = 0;
+
+            if( (double)(Math.Abs(d))<(double)(Math.Abs(c)) )
+            {
+                e = d/c;
+                f = c+d*e;
+                p = (a+b*e)/f;
+                q = (b-a*e)/f;
+            }
+            else
+            {
+                e = c/d;
+                f = d+c*e;
+                p = (b+a*e)/f;
+                q = (-a+b*e)/f;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/odesolver.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/odesolver.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/odesolver.cs	(revision 2645)
@@ -0,0 +1,717 @@
+/*************************************************************************
+Copyright 2009 by Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class odesolver
+    {
+        public struct odesolverstate
+        {
+            public int n;
+            public int m;
+            public double xscale;
+            public double h;
+            public double eps;
+            public bool fraceps;
+            public double[] yc;
+            public double[] escale;
+            public double[] xg;
+            public int solvertype;
+            public double x;
+            public double[] y;
+            public double[] dy;
+            public double[,] ytbl;
+            public int repterminationtype;
+            public int repnfev;
+            public double[] yn;
+            public double[] yns;
+            public double[] rka;
+            public double[] rkc;
+            public double[] rkcs;
+            public double[,] rkb;
+            public double[,] rkk;
+            public AP.rcommstate rstate;
+        };
+
+
+        public struct odesolverreport
+        {
+            public int nfev;
+            public int terminationtype;
+        };
+
+
+
+
+        public const double odesolvermaxgrow = 3.0;
+        public const double odesolvermaxshrink = 10.0;
+
+
+        /*************************************************************************
+        Cash-Karp adaptive ODE solver.
+
+        This subroutine solves ODE  Y'=f(Y,x)  with  initial  conditions  Y(xs)=Ys
+        (here Y may be single variable or vector of N variables).
+
+        INPUT PARAMETERS:
+            Y       -   initial conditions, array[0..N-1].
+                        contains values of Y[] at X[0]
+            N       -   system size
+            X       -   points at which Y should be tabulated, array[0..M-1]
+                        integrations starts at X[0], ends at X[M-1],  intermediate
+                        values at X[i] are returned too.
+                        SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!!!
+            M       -   number of intermediate points + first point + last point:
+                        * M>2 means that you need both Y(X[M-1]) and M-2 values at
+                          intermediate points
+                        * M=2 means that you want just to integrate from  X[0]  to
+                          X[1] and don't interested in intermediate values.
+                        * M=1 means that you don't want to integrate :)
+                          it is degenerate case, but it will be handled correctly.
+                        * M<1 means error
+            Eps     -   tolerance (absolute/relative error on each  step  will  be
+                        less than Eps). When passing:
+                        * Eps>0, it means desired ABSOLUTE error
+                        * Eps<0, it means desired RELATIVE error.  Relative errors
+                          are calculated with respect to maximum values of  Y seen
+                          so far. Be careful to use this criterion  when  starting
+                          from Y[] that are close to zero.
+            H       -   initial  step  lenth,  it  will  be adjusted automatically
+                        after the first  step.  If  H=0,  step  will  be  selected
+                        automatically  (usualy  it  will  be  equal  to  0.001  of
+                        min(x[i]-x[j])).
+
+        OUTPUT PARAMETERS
+            State   -   structure which stores algorithm state between  subsequent
+                        calls of OdeSolverIteration. Used for reverse communication.
+                        This structure should be passed  to the OdeSolverIteration
+                        subroutine.
+
+        SEE ALSO
+            AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults.
+
+
+          -- ALGLIB --
+             Copyright 01.09.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void odesolverrkck(ref double[] y,
+            int n,
+            ref double[] x,
+            int m,
+            double eps,
+            double h,
+            ref odesolverstate state)
+        {
+            odesolverinit(0, ref y, n, ref x, m, eps, h, ref state);
+        }
+
+
+        /*************************************************************************
+        One iteration of ODE solver.
+
+        Called after inialization of State structure with OdeSolverXXX subroutine.
+        See HTML docs for examples.
+
+        INPUT PARAMETERS:
+            State   -   structure which stores algorithm state between subsequent
+                        calls and which is used for reverse communication. Must be
+                        initialized with OdeSolverXXX() call first.
+
+        If subroutine returned False, algorithm have finished its work.
+        If subroutine returned True, then user should:
+        * calculate F(State.X, State.Y)
+        * store it in State.DY
+        Here State.X is real, State.Y and State.DY are arrays[0..N-1] of reals.
+
+          -- ALGLIB --
+             Copyright 01.09.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool odesolveriteration(ref odesolverstate state)
+        {
+            bool result = new bool();
+            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 = new bool();
+            double err = 0;
+            double maxgrowpow = 0;
+            int klimit = 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.rstate.stage>=0 )
+            {
+                n = state.rstate.ia[0];
+                m = state.rstate.ia[1];
+                i = state.rstate.ia[2];
+                j = state.rstate.ia[3];
+                k = state.rstate.ia[4];
+                klimit = state.rstate.ia[5];
+                gridpoint = state.rstate.ba[0];
+                xc = state.rstate.ra[0];
+                v = state.rstate.ra[1];
+                h = state.rstate.ra[2];
+                h2 = state.rstate.ra[3];
+                err = state.rstate.ra[4];
+                maxgrowpow = state.rstate.ra[5];
+            }
+            else
+            {
+                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;
+            }
+            if( state.rstate.stage==0 )
+            {
+                goto lbl_0;
+            }
+            
+            //
+            // Routine body
+            //
+            
+            //
+            // prepare
+            //
+            if( state.repterminationtype!=0 )
+            {
+                result = false;
+                return result;
+            }
+            n = state.n;
+            m = state.m;
+            h = state.h;
+            state.y = new double[n];
+            state.dy = new double[n];
+            maxgrowpow = Math.Pow(odesolvermaxgrow, 5);
+            state.repnfev = 0;
+            
+            //
+            // some preliminary checks for internal errors
+            // after this we assume that H>0 and M>1
+            //
+            System.Diagnostics.Debug.Assert((double)(state.h)>(double)(0), "ODESolver: internal error");
+            System.Diagnostics.Debug.Assert(m>1, "ODESolverIteration: internal error");
+            
+            //
+            // choose solver
+            //
+            if( state.solvertype!=0 )
+            {
+                goto lbl_1;
+            }
+            
+            //
+            // Cask-Karp solver
+            // Prepare coefficients table.
+            // Check it for errors
+            //
+            state.rka = new double[6];
+            state.rka[0] = 0;
+            state.rka[1] = (double)(1)/(double)(5);
+            state.rka[2] = (double)(3)/(double)(10);
+            state.rka[3] = (double)(3)/(double)(5);
+            state.rka[4] = 1;
+            state.rka[5] = (double)(7)/(double)(8);
+            state.rkb = new double[6, 5];
+            state.rkb[1,0] = (double)(1)/(double)(5);
+            state.rkb[2,0] = (double)(3)/(double)(40);
+            state.rkb[2,1] = (double)(9)/(double)(40);
+            state.rkb[3,0] = (double)(3)/(double)(10);
+            state.rkb[3,1] = -((double)(9)/(double)(10));
+            state.rkb[3,2] = (double)(6)/(double)(5);
+            state.rkb[4,0] = -((double)(11)/(double)(54));
+            state.rkb[4,1] = (double)(5)/(double)(2);
+            state.rkb[4,2] = -((double)(70)/(double)(27));
+            state.rkb[4,3] = (double)(35)/(double)(27);
+            state.rkb[5,0] = (double)(1631)/(double)(55296);
+            state.rkb[5,1] = (double)(175)/(double)(512);
+            state.rkb[5,2] = (double)(575)/(double)(13824);
+            state.rkb[5,3] = (double)(44275)/(double)(110592);
+            state.rkb[5,4] = (double)(253)/(double)(4096);
+            state.rkc = new double[6];
+            state.rkc[0] = (double)(37)/(double)(378);
+            state.rkc[1] = 0;
+            state.rkc[2] = (double)(250)/(double)(621);
+            state.rkc[3] = (double)(125)/(double)(594);
+            state.rkc[4] = 0;
+            state.rkc[5] = (double)(512)/(double)(1771);
+            state.rkcs = new double[6];
+            state.rkcs[0] = (double)(2825)/(double)(27648);
+            state.rkcs[1] = 0;
+            state.rkcs[2] = (double)(18575)/(double)(48384);
+            state.rkcs[3] = (double)(13525)/(double)(55296);
+            state.rkcs[4] = (double)(277)/(double)(14336);
+            state.rkcs[5] = (double)(1)/(double)(4);
+            state.rkk = new double[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.ytbl = new double[m, n];
+            state.escale = new double[n];
+            state.yn = new double[n];
+            state.yns = new double[n];
+            xc = state.xg[0];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.ytbl[0,i_] = state.yc[i_];
+            }
+            for(j=0; j<=n-1; j++)
+            {
+                state.escale[j] = 0;
+            }
+            i = 1;
+        lbl_3:
+            if( i>m-1 )
+            {
+                goto lbl_5;
+            }
+            
+            //
+            // begin inner iteration
+            //
+        lbl_6:
+            if( false )
+            {
+                goto lbl_7;
+            }
+            
+            //
+            // truncate step if needed (beyond right boundary).
+            // determine should we store X or not
+            //
+            if( (double)(xc+h)>=(double)(state.xg[i]) )
+            {
+                h = state.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.escale[j] = Math.Max(state.escale[j], Math.Abs(state.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(i_=0; i_<=n-1;i_++)
+            {
+                state.yn[i_] = state.yc[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.yns[i_] = state.yc[i_];
+            }
+            k = 0;
+        lbl_8:
+            if( k>5 )
+            {
+                goto lbl_10;
+            }
+            
+            //
+            // prepare data for the next update of YN/YNS
+            //
+            state.x = state.xscale*(xc+state.rka[k]*h);
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.y[i_] = state.yc[i_];
+            }
+            for(j=0; j<=k-1; j++)
+            {
+                v = state.rkb[k,j];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.y[i_] = state.y[i_] + v*state.rkk[j,i_];
+                }
+            }
+            state.rstate.stage = 0;
+            goto lbl_rcomm;
+        lbl_0:
+            state.repnfev = state.repnfev+1;
+            v = h*state.xscale;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.rkk[k,i_] = v*state.dy[i_];
+            }
+            
+            //
+            // update YN/YNS
+            //
+            v = state.rkc[k];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.yn[i_] = state.yn[i_] + v*state.rkk[k,i_];
+            }
+            v = state.rkcs[k];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.yns[i_] = state.yns[i_] + v*state.rkk[k,i_];
+            }
+            k = k+1;
+            goto lbl_8;
+        lbl_10:
+            
+            //
+            // estimate error
+            //
+            err = 0;
+            for(j=0; j<=n-1; j++)
+            {
+                if( !state.fraceps )
+                {
+                    
+                    //
+                    // absolute error is estimated
+                    //
+                    err = Math.Max(err, Math.Abs(state.yn[j]-state.yns[j]));
+                }
+                else
+                {
+                    
+                    //
+                    // Relative error is estimated
+                    //
+                    v = state.escale[j];
+                    if( (double)(v)==(double)(0) )
+                    {
+                        v = 1;
+                    }
+                    err = Math.Max(err, Math.Abs(state.yn[j]-state.yns[j])/v);
+                }
+            }
+            
+            //
+            // calculate new step, restart if necessary
+            //
+            if( (double)(maxgrowpow*err)<=(double)(state.eps) )
+            {
+                h2 = odesolvermaxgrow*h;
+            }
+            else
+            {
+                h2 = h*Math.Pow(state.eps/err, 0.2);
+            }
+            if( (double)(h2)<(double)(h/odesolvermaxshrink) )
+            {
+                h2 = h/odesolvermaxshrink;
+            }
+            if( (double)(err)>(double)(state.eps) )
+            {
+                h = h2;
+                goto lbl_6;
+            }
+            
+            //
+            // advance position
+            //
+            xc = xc+h;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.yc[i_] = state.yn[i_];
+            }
+            
+            //
+            // update H
+            //
+            h = h2;
+            
+            //
+            // break on grid point
+            //
+            if( gridpoint )
+            {
+                goto lbl_7;
+            }
+            goto lbl_6;
+        lbl_7:
+            
+            //
+            // save result
+            //
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.ytbl[i,i_] = state.yc[i_];
+            }
+            i = i+1;
+            goto lbl_3;
+        lbl_5:
+            state.repterminationtype = 1;
+            result = false;
+            return result;
+        lbl_1:
+            result = false;
+            return result;
+            
+            //
+            // Saving state
+            //
+        lbl_rcomm:
+            result = true;
+            state.rstate.ia[0] = n;
+            state.rstate.ia[1] = m;
+            state.rstate.ia[2] = i;
+            state.rstate.ia[3] = j;
+            state.rstate.ia[4] = k;
+            state.rstate.ia[5] = klimit;
+            state.rstate.ba[0] = gridpoint;
+            state.rstate.ra[0] = xc;
+            state.rstate.ra[1] = v;
+            state.rstate.ra[2] = h;
+            state.rstate.ra[3] = h2;
+            state.rstate.ra[4] = err;
+            state.rstate.ra[5] = maxgrowpow;
+            return result;
+        }
+
+
+        /*************************************************************************
+        ODE solver results
+
+        Called after OdeSolverIteration returned False.
+
+        INPUT PARAMETERS:
+            State   -   algorithm state (used by OdeSolverIteration).
+
+        OUTPUT PARAMETERS:
+            M       -   number of tabulated values, M>=1
+            XTbl    -   array[0..M-1], values of X
+            YTbl    -   array[0..M-1,0..N-1], values of Y in X[i]
+            Rep     -   solver report:
+                        * Rep.TerminationType completetion code:
+                            * -2    X is not ordered  by  ascending/descending  or
+                                    there are non-distinct X[],  i.e.  X[i]=X[i+1]
+                            * -1    incorrect parameters were specified
+                            *  1    task has been solved
+                        * Rep.NFEV contains number of function calculations
+
+          -- ALGLIB --
+             Copyright 01.09.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void odesolverresults(ref odesolverstate state,
+            ref int m,
+            ref double[] xtbl,
+            ref double[,] ytbl,
+            ref odesolverreport rep)
+        {
+            double v = 0;
+            int i = 0;
+            int i_ = 0;
+
+            rep.terminationtype = state.repterminationtype;
+            if( rep.terminationtype>0 )
+            {
+                m = state.m;
+                rep.nfev = state.repnfev;
+                xtbl = new double[state.m];
+                v = state.xscale;
+                for(i_=0; i_<=state.m-1;i_++)
+                {
+                    xtbl[i_] = v*state.xg[i_];
+                }
+                ytbl = new double[state.m, state.n];
+                for(i=0; i<=state.m-1; i++)
+                {
+                    for(i_=0; i_<=state.n-1;i_++)
+                    {
+                        ytbl[i,i_] = state.ytbl[i,i_];
+                    }
+                }
+            }
+            else
+            {
+                rep.nfev = 0;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal initialization subroutine
+        *************************************************************************/
+        private static void odesolverinit(int solvertype,
+            ref double[] y,
+            int n,
+            ref double[] x,
+            int m,
+            double eps,
+            double h,
+            ref odesolverstate state)
+        {
+            int i = 0;
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            // Prepare RComm
+            //
+            state.rstate.ia = new int[5+1];
+            state.rstate.ba = new bool[0+1];
+            state.rstate.ra = new double[5+1];
+            state.rstate.stage = -1;
+            
+            //
+            // check parameters.
+            //
+            if( n<=0 | m<1 | (double)(eps)==(double)(0) )
+            {
+                state.repterminationtype = -1;
+                return;
+            }
+            if( (double)(h)<(double)(0) )
+            {
+                h = -h;
+            }
+            
+            //
+            // quick exit if necessary.
+            // after this block we assume that M>1
+            //
+            if( m==1 )
+            {
+                state.repnfev = 0;
+                state.repterminationtype = 1;
+                state.ytbl = new double[1, n];
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    state.ytbl[0,i_] = y[i_];
+                }
+                state.xg = new double[m];
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    state.xg[i_] = x[i_];
+                }
+                return;
+            }
+            
+            //
+            // check again: correct order of X[]
+            //
+            if( (double)(x[1])==(double)(x[0]) )
+            {
+                state.repterminationtype = -2;
+                return;
+            }
+            for(i=1; i<=m-1; i++)
+            {
+                if( (double)(x[1])>(double)(x[0]) & (double)(x[i])<=(double)(x[i-1]) | (double)(x[1])<(double)(x[0]) & (double)(x[i])>=(double)(x[i-1]) )
+                {
+                    state.repterminationtype = -2;
+                    return;
+                }
+            }
+            
+            //
+            // auto-select H if necessary
+            //
+            if( (double)(h)==(double)(0) )
+            {
+                v = Math.Abs(x[1]-x[0]);
+                for(i=2; i<=m-1; i++)
+                {
+                    v = Math.Min(v, Math.Abs(x[i]-x[i-1]));
+                }
+                h = 0.001*v;
+            }
+            
+            //
+            // store parameters
+            //
+            state.n = n;
+            state.m = m;
+            state.h = h;
+            state.eps = Math.Abs(eps);
+            state.fraceps = (double)(eps)<(double)(0);
+            state.xg = new double[m];
+            for(i_=0; i_<=m-1;i_++)
+            {
+                state.xg[i_] = x[i_];
+            }
+            if( (double)(x[1])>(double)(x[0]) )
+            {
+                state.xscale = 1;
+            }
+            else
+            {
+                state.xscale = -1;
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    state.xg[i_] = -1*state.xg[i_];
+                }
+            }
+            state.yc = new double[n];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                state.yc[i_] = y[i_];
+            }
+            state.solvertype = solvertype;
+            state.repterminationtype = 0;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/pca.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/pca.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/pca.cs	(revision 2645)
@@ -0,0 +1,168 @@
+/*************************************************************************
+Copyright (c) 2008, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class pca
+    {
+        /*************************************************************************
+        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
+
+        ÂÛÕÎÄÍÛÅ ÏÀÐÀÌÅÒÐÛ:
+            Info        -   return code:
+                            * -4, if SVD subroutine haven't converged
+                            * -1, if wrong parameters has been passed (NPoints<0,
+                                  NVars<1)
+                            *  1, if task is solved
+            S2          -   array[0..NVars-1]. variance values corresponding
+                            to basis vectors.
+            V           -   array[0..NVars-1,0..NVars-1]
+                            matrix, whose columns store basis vectors.
+
+          -- ALGLIB --
+             Copyright 25.08.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void pcabuildbasis(ref double[,] x,
+            int npoints,
+            int nvars,
+            ref int info,
+            ref double[] s2,
+            ref double[,] v)
+        {
+            double[,] a = new double[0,0];
+            double[,] u = new double[0,0];
+            double[,] vt = new double[0,0];
+            double[] m = new double[0];
+            double[] t = new double[0];
+            int i = 0;
+            int j = 0;
+            double mean = 0;
+            double variance = 0;
+            double skewness = 0;
+            double kurtosis = 0;
+            int i_ = 0;
+
+            
+            //
+            // Check input data
+            //
+            if( npoints<0 | nvars<1 )
+            {
+                info = -1;
+                return;
+            }
+            info = 1;
+            
+            //
+            // Special case: NPoints=0
+            //
+            if( npoints==0 )
+            {
+                s2 = new double[nvars-1+1];
+                v = new double[nvars-1+1, nvars-1+1];
+                for(i=0; i<=nvars-1; i++)
+                {
+                    s2[i] = 0;
+                }
+                for(i=0; i<=nvars-1; i++)
+                {
+                    for(j=0; j<=nvars-1; j++)
+                    {
+                        if( i==j )
+                        {
+                            v[i,j] = 1;
+                        }
+                        else
+                        {
+                            v[i,j] = 0;
+                        }
+                    }
+                }
+                return;
+            }
+            
+            //
+            // Calculate means
+            //
+            m = new double[nvars-1+1];
+            t = new double[npoints-1+1];
+            for(j=0; j<=nvars-1; j++)
+            {
+                for(i_=0; i_<=npoints-1;i_++)
+                {
+                    t[i_] = x[i_,j];
+                }
+                descriptivestatistics.calculatemoments(ref t, npoints, ref mean, ref variance, ref skewness, ref kurtosis);
+                m[j] = mean;
+            }
+            
+            //
+            // Center, apply SVD, prepare output
+            //
+            a = new double[Math.Max(npoints, nvars)-1+1, nvars-1+1];
+            for(i=0; i<=npoints-1; i++)
+            {
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    a[i,i_] = x[i,i_];
+                }
+                for(i_=0; i_<=nvars-1;i_++)
+                {
+                    a[i,i_] = a[i,i_] - m[i_];
+                }
+            }
+            for(i=npoints; i<=nvars-1; i++)
+            {
+                for(j=0; j<=nvars-1; j++)
+                {
+                    a[i,j] = 0;
+                }
+            }
+            if( !svd.rmatrixsvd(a, Math.Max(npoints, nvars), nvars, 0, 1, 2, ref s2, ref u, ref vt) )
+            {
+                info = -4;
+                return;
+            }
+            if( npoints!=1 )
+            {
+                for(i=0; i<=nvars-1; i++)
+                {
+                    s2[i] = AP.Math.Sqr(s2[i])/(npoints-1);
+                }
+            }
+            v = new double[nvars-1+1, nvars-1+1];
+            blas.copyandtranspose(ref vt, 0, nvars-1, 0, nvars-1, ref v, 0, nvars-1, 0, nvars-1);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/poissondistr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/poissondistr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/poissondistr.cs	(revision 2645)
@@ -0,0 +1,136 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class poissondistr
+    {
+        /*************************************************************************
+        Poisson distribution
+
+        Returns the sum of the first k+1 terms of the Poisson
+        distribution:
+
+          k         j
+          --   -m  m
+          >   e    --
+          --       j!
+         j=0
+
+        The terms are not summed directly; instead the incomplete
+        gamma integral is employed, according to the relation
+
+        y = pdtr( k, m ) = igamc( k+1, m ).
+
+        The arguments must both be positive.
+        ACCURACY:
+
+        See incomplete gamma function
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double poissondistribution(int k,
+            double m)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert(k>=0 & (double)(m)>(double)(0), "Domain error in PoissonDistribution");
+            result = igammaf.incompletegammac(k+1, m);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Complemented Poisson distribution
+
+        Returns the sum of the terms k+1 to infinity of the Poisson
+        distribution:
+
+         inf.       j
+          --   -m  m
+          >   e    --
+          --       j!
+         j=k+1
+
+        The terms are not summed directly; instead the incomplete
+        gamma integral is employed, according to the formula
+
+        y = pdtrc( k, m ) = igam( k+1, m ).
+
+        The arguments must both be positive.
+
+        ACCURACY:
+
+        See incomplete gamma function
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double poissoncdistribution(int k,
+            double m)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert(k>=0 & (double)(m)>(double)(0), "Domain error in PoissonDistributionC");
+            result = igammaf.incompletegamma(k+1, m);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inverse Poisson distribution
+
+        Finds the Poisson variable x such that the integral
+        from 0 to x of the Poisson density is equal to the
+        given probability y.
+
+        This is accomplished using the inverse gamma integral
+        function and the relation
+
+           m = igami( k+1, y ).
+
+        ACCURACY:
+
+        See inverse incomplete gamma function
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invpoissondistribution(int k,
+            double y)
+        {
+            double result = 0;
+
+            System.Diagnostics.Debug.Assert(k>=0 & (double)(y)>=(double)(0) & (double)(y)<(double)(1), "Domain error in InvPoissonDistribution");
+            result = igammaf.invincompletegammac(k+1, y);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/polint.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/polint.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/polint.cs	(revision 2645)
@@ -0,0 +1,1236 @@
+/*************************************************************************
+Copyright (c) 2006-2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class polint
+    {
+        /*************************************************************************
+        Polynomial fitting report:
+            TaskRCond       reciprocal of task's condition number
+            RMSError        RMS error
+            AvgError        average error
+            AvgRelError     average relative error (for non-zero Y[I])
+            MaxError        maximum error
+        *************************************************************************/
+        public struct polynomialfitreport
+        {
+            public double taskrcond;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+            public double maxerror;
+        };
+
+
+
+
+        /*************************************************************************
+        Lagrange intepolant: generation of the model on the general grid.
+        This function has O(N^2) complexity.
+
+        INPUT PARAMETERS:
+            X   -   abscissas, array[0..N-1]
+            Y   -   function values, array[0..N-1]
+            N   -   number of points, N>=1
+
+        OIYTPUT PARAMETERS
+            P   -   barycentric model which represents Lagrange interpolant
+                    (see ratint unit info and BarycentricCalc() description for
+                    more information).
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void polynomialbuild(ref double[] x,
+            ref double[] y,
+            int n,
+            ref ratint.barycentricinterpolant p)
+        {
+            int j = 0;
+            int k = 0;
+            double[] w = new double[0];
+            double b = 0;
+            double a = 0;
+            double v = 0;
+            double mx = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntBuild: N<=0!");
+            
+            //
+            // calculate W[j]
+            // multi-pass algorithm is used to avoid overflow
+            //
+            w = new double[n];
+            a = x[0];
+            b = x[0];
+            for(j=0; j<=n-1; j++)
+            {
+                w[j] = 1;
+                a = Math.Min(a, x[j]);
+                b = Math.Max(b, x[j]);
+            }
+            for(k=0; k<=n-1; k++)
+            {
+                
+                //
+                // W[K] is used instead of 0.0 because
+                // cycle on J does not touch K-th element
+                // and we MUST get maximum from ALL elements
+                //
+                mx = Math.Abs(w[k]);
+                for(j=0; j<=n-1; j++)
+                {
+                    if( j!=k )
+                    {
+                        v = (b-a)/(x[j]-x[k]);
+                        w[j] = w[j]*v;
+                        mx = Math.Max(mx, Math.Abs(w[j]));
+                    }
+                }
+                if( k%5==0 )
+                {
+                    
+                    //
+                    // every 5-th run we renormalize W[]
+                    //
+                    v = 1/mx;
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        w[i_] = v*w[i_];
+                    }
+                }
+            }
+            ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p);
+        }
+
+
+        /*************************************************************************
+        Lagrange intepolant: generation of the model on equidistant grid.
+        This function has O(N) complexity.
+
+        INPUT PARAMETERS:
+            A   -   left boundary of [A,B]
+            B   -   right boundary of [A,B]
+            Y   -   function values at the nodes, array[0..N-1]
+            N   -   number of points, N>=1
+                    for N=1 a constant model is constructed.
+
+        OIYTPUT PARAMETERS
+            P   -   barycentric model which represents Lagrange interpolant
+                    (see ratint unit info and BarycentricCalc() description for
+                    more information).
+
+          -- ALGLIB --
+             Copyright 03.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void polynomialbuildeqdist(double a,
+            double b,
+            ref double[] y,
+            int n,
+            ref ratint.barycentricinterpolant p)
+        {
+            int i = 0;
+            double[] w = new double[0];
+            double[] x = new double[0];
+            double v = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntBuildEqDist: N<=0!");
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                x = new double[1];
+                w = new double[1];
+                x[0] = 0.5*(b+a);
+                w[0] = 1;
+                ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref p);
+                return;
+            }
+            
+            //
+            // general case
+            //
+            x = new double[n];
+            w = new double[n];
+            v = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                w[i] = v;
+                x[i] = a+(b-a)*i/(n-1);
+                v = -(v*(n-1-i));
+                v = v/(i+1);
+            }
+            ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p);
+        }
+
+
+        /*************************************************************************
+        Lagrange intepolant on Chebyshev grid (first kind).
+        This function has O(N) complexity.
+
+        INPUT PARAMETERS:
+            A   -   left boundary of [A,B]
+            B   -   right boundary of [A,B]
+            Y   -   function values at the nodes, array[0..N-1],
+                    Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
+            N   -   number of points, N>=1
+                    for N=1 a constant model is constructed.
+
+        OIYTPUT PARAMETERS
+            P   -   barycentric model which represents Lagrange interpolant
+                    (see ratint unit info and BarycentricCalc() description for
+                    more information).
+
+          -- ALGLIB --
+             Copyright 03.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void polynomialbuildcheb1(double a,
+            double b,
+            ref double[] y,
+            int n,
+            ref ratint.barycentricinterpolant p)
+        {
+            int i = 0;
+            double[] w = new double[0];
+            double[] x = new double[0];
+            double v = 0;
+            double t = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntBuildCheb1: N<=0!");
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                x = new double[1];
+                w = new double[1];
+                x[0] = 0.5*(b+a);
+                w[0] = 1;
+                ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref p);
+                return;
+            }
+            
+            //
+            // general case
+            //
+            x = new double[n];
+            w = new double[n];
+            v = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                t = Math.Tan(0.5*Math.PI*(2*i+1)/(2*n));
+                w[i] = 2*v*t/(1+AP.Math.Sqr(t));
+                x[i] = 0.5*(b+a)+0.5*(b-a)*(1-AP.Math.Sqr(t))/(1+AP.Math.Sqr(t));
+                v = -v;
+            }
+            ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p);
+        }
+
+
+        /*************************************************************************
+        Lagrange intepolant on Chebyshev grid (second kind).
+        This function has O(N) complexity.
+
+        INPUT PARAMETERS:
+            A   -   left boundary of [A,B]
+            B   -   right boundary of [A,B]
+            Y   -   function values at the nodes, array[0..N-1],
+                    Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
+            N   -   number of points, N>=1
+                    for N=1 a constant model is constructed.
+
+        OIYTPUT PARAMETERS
+            P   -   barycentric model which represents Lagrange interpolant
+                    (see ratint unit info and BarycentricCalc() description for
+                    more information).
+
+          -- ALGLIB --
+             Copyright 03.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void polynomialbuildcheb2(double a,
+            double b,
+            ref double[] y,
+            int n,
+            ref ratint.barycentricinterpolant p)
+        {
+            int i = 0;
+            double[] w = new double[0];
+            double[] x = new double[0];
+            double v = 0;
+            double t = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntBuildCheb2: N<=0!");
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                x = new double[1];
+                w = new double[1];
+                x[0] = 0.5*(b+a);
+                w[0] = 1;
+                ratint.barycentricbuildxyw(ref x, ref y, ref w, 1, ref p);
+                return;
+            }
+            
+            //
+            // general case
+            //
+            x = new double[n];
+            w = new double[n];
+            v = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                if( i==0 | i==n-1 )
+                {
+                    w[i] = v*0.5;
+                }
+                else
+                {
+                    w[i] = v;
+                }
+                x[i] = 0.5*(b+a)+0.5*(b-a)*Math.Cos(Math.PI*i/(n-1));
+                v = -v;
+            }
+            ratint.barycentricbuildxyw(ref x, ref y, ref w, n, ref p);
+        }
+
+
+        /*************************************************************************
+        Fast equidistant polynomial interpolation function with O(N) complexity
+
+        INPUT PARAMETERS:
+            A   -   left boundary of [A,B]
+            B   -   right boundary of [A,B]
+            F   -   function values, array[0..N-1]
+            N   -   number of points on equidistant grid, N>=1
+                    for N=1 a constant model is constructed.
+            T   -   position where P(x) is calculated
+
+        RESULT
+            value of the Lagrange interpolant at T
+            
+        IMPORTANT
+            this function provides fast interface which is not overflow-safe
+            nor it is very precise.
+            the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
+            subroutines unless you are pretty sure that your data will not result
+            in overflow.
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double polynomialcalceqdist(double a,
+            double b,
+            ref double[] f,
+            int n,
+            double t)
+        {
+            double result = 0;
+            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;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntEqDist: N<=0!");
+            threshold = Math.Sqrt(AP.Math.MinRealNumber);
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                result = f[0];
+                return result;
+            }
+            
+            //
+            // First, decide: should we use "safe" formula (guarded
+            // against overflow) or fast one?
+            //
+            j = 0;
+            s = t-a;
+            for(i=1; i<=n-1; i++)
+            {
+                x = a+(double)(i)/((double)(n-1))*(b-a);
+                if( (double)(Math.Abs(t-x))<(double)(Math.Abs(s)) )
+                {
+                    s = t-x;
+                    j = i;
+                }
+            }
+            if( (double)(s)==(double)(0) )
+            {
+                result = f[j];
+                return result;
+            }
+            if( (double)(Math.Abs(s))>(double)(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);
+            for(i=0; i<=n-1; i++)
+            {
+                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;
+                }
+                w = -(w*(n-1-i));
+                w = w/(i+1);
+            }
+            result = s1/s2;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Fast polynomial interpolation function on Chebyshev points (first kind)
+        with O(N) complexity.
+
+        INPUT PARAMETERS:
+            A   -   left boundary of [A,B]
+            B   -   right boundary of [A,B]
+            F   -   function values, array[0..N-1]
+            N   -   number of points on Chebyshev grid (first kind),
+                    X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
+                    for N=1 a constant model is constructed.
+            T   -   position where P(x) is calculated
+
+        RESULT
+            value of the Lagrange interpolant at T
+
+        IMPORTANT
+            this function provides fast interface which is not overflow-safe
+            nor it is very precise.
+            the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
+            subroutines unless you are pretty sure that your data will not result
+            in overflow.
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double polynomialcalccheb1(double a,
+            double b,
+            ref double[] f,
+            int n,
+            double t)
+        {
+            double result = 0;
+            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;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntCheb1: N<=0!");
+            threshold = Math.Sqrt(AP.Math.MinRealNumber);
+            t = (t-0.5*(a+b))/(0.5*(b-a));
+            
+            //
+            // Fast exit
+            //
+            if( n==1 )
+            {
+                result = f[0];
+                return result;
+            }
+            
+            //
+            // Prepare information for the recurrence formula
+            // used to calculate sin(pi*(2j+1)/(2n+2)) and
+            // cos(pi*(2j+1)/(2n+2)):
+            //
+            // A0    = pi/(2n+2)
+            // Delta = pi/(n+1)
+            // Alpha = 2 sin^2 (Delta/2)
+            // Beta  = sin(Delta)
+            //
+            // so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta).
+            // Then we use
+            //
+            // sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x))
+            // cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x))
+            //
+            // to repeatedly calculate sin(..) and cos(..).
+            //
+            a0 = Math.PI/(2*(n-1)+2);
+            delta = 2*Math.PI/(2*(n-1)+2);
+            alpha = 2*AP.Math.Sqr(Math.Sin(delta/2));
+            beta = Math.Sin(delta);
+            
+            //
+            // First, decide: should we use "safe" formula (guarded
+            // against overflow) or fast one?
+            //
+            ca = Math.Cos(a0);
+            sa = Math.Sin(a0);
+            j = 0;
+            x = ca;
+            s = t-x;
+            for(i=1; i<=n-1; i++)
+            {
+                
+                //
+                // Next X[i]
+                //
+                temps = sa-(alpha*sa-beta*ca);
+                tempc = ca-(alpha*ca+beta*sa);
+                sa = temps;
+                ca = tempc;
+                x = ca;
+                
+                //
+                // Use X[i]
+                //
+                if( (double)(Math.Abs(t-x))<(double)(Math.Abs(s)) )
+                {
+                    s = t-x;
+                    j = i;
+                }
+            }
+            if( (double)(s)==(double)(0) )
+            {
+                result = f[j];
+                return result;
+            }
+            if( (double)(Math.Abs(s))>(double)(threshold) )
+            {
+                
+                //
+                // use fast formula
+                //
+                j = -1;
+                s = 1.0;
+            }
+            
+            //
+            // Calculate using safe or fast barycentric formula
+            //
+            s1 = 0;
+            s2 = 0;
+            ca = Math.Cos(a0);
+            sa = Math.Sin(a0);
+            p1 = 1.0;
+            for(i=0; i<=n-1; i++)
+            {
+                
+                //
+                // Calculate X[i], W[i]
+                //
+                x = ca;
+                w = p1*sa;
+                
+                //
+                // Proceed
+                //
+                if( i!=j )
+                {
+                    v = s*w/(t-x);
+                    s1 = s1+v*f[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;
+            }
+            result = s1/s2;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Fast polynomial interpolation function on Chebyshev points (second kind)
+        with O(N) complexity.
+
+        INPUT PARAMETERS:
+            A   -   left boundary of [A,B]
+            B   -   right boundary of [A,B]
+            F   -   function values, array[0..N-1]
+            N   -   number of points on Chebyshev grid (second kind),
+                    X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
+                    for N=1 a constant model is constructed.
+            T   -   position where P(x) is calculated
+
+        RESULT
+            value of the Lagrange interpolant at T
+
+        IMPORTANT
+            this function provides fast interface which is not overflow-safe
+            nor it is very precise.
+            the best option is to use PolIntBuildCheb2()/BarycentricCalc()
+            subroutines unless you are pretty sure that your data will not result
+            in overflow.
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double polynomialcalccheb2(double a,
+            double b,
+            ref double[] f,
+            int n,
+            double t)
+        {
+            double result = 0;
+            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;
+
+            System.Diagnostics.Debug.Assert(n>0, "PolIntCheb2: N<=0!");
+            threshold = Math.Sqrt(AP.Math.MinRealNumber);
+            t = (t-0.5*(a+b))/(0.5*(b-a));
+            
+            //
+            // Fast exit
+            //
+            if( n==1 )
+            {
+                result = f[0];
+                return result;
+            }
+            
+            //
+            // Prepare information for the recurrence formula
+            // used to calculate sin(pi*i/n) and
+            // cos(pi*i/n):
+            //
+            // A0    = 0
+            // Delta = pi/n
+            // Alpha = 2 sin^2 (Delta/2)
+            // Beta  = sin(Delta)
+            //
+            // so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta).
+            // Then we use
+            //
+            // sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x))
+            // cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x))
+            //
+            // to repeatedly calculate sin(..) and cos(..).
+            //
+            a0 = 0.0;
+            delta = Math.PI/(n-1);
+            alpha = 2*AP.Math.Sqr(Math.Sin(delta/2));
+            beta = Math.Sin(delta);
+            
+            //
+            // First, decide: should we use "safe" formula (guarded
+            // against overflow) or fast one?
+            //
+            ca = Math.Cos(a0);
+            sa = Math.Sin(a0);
+            j = 0;
+            x = ca;
+            s = t-x;
+            for(i=1; i<=n-1; i++)
+            {
+                
+                //
+                // Next X[i]
+                //
+                temps = sa-(alpha*sa-beta*ca);
+                tempc = ca-(alpha*ca+beta*sa);
+                sa = temps;
+                ca = tempc;
+                x = ca;
+                
+                //
+                // Use X[i]
+                //
+                if( (double)(Math.Abs(t-x))<(double)(Math.Abs(s)) )
+                {
+                    s = t-x;
+                    j = i;
+                }
+            }
+            if( (double)(s)==(double)(0) )
+            {
+                result = f[j];
+                return result;
+            }
+            if( (double)(Math.Abs(s))>(double)(threshold) )
+            {
+                
+                //
+                // use fast formula
+                //
+                j = -1;
+                s = 1.0;
+            }
+            
+            //
+            // Calculate using safe or fast barycentric formula
+            //
+            s1 = 0;
+            s2 = 0;
+            ca = Math.Cos(a0);
+            sa = Math.Sin(a0);
+            p1 = 1.0;
+            for(i=0; i<=n-1; i++)
+            {
+                
+                //
+                // Calculate X[i], W[i]
+                //
+                x = ca;
+                if( i==0 | i==n-1 )
+                {
+                    w = 0.5*p1;
+                }
+                else
+                {
+                    w = 1.0*p1;
+                }
+                
+                //
+                // Proceed
+                //
+                if( i!=j )
+                {
+                    v = s*w/(t-x);
+                    s1 = s1+v*f[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;
+            }
+            result = s1/s2;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Least squares fitting by polynomial.
+
+        This subroutine is "lightweight" alternative for more complex and feature-
+        rich PolynomialFitWC().  See  PolynomialFitWC() for more information about
+        subroutine parameters (we don't duplicate it here because of length)
+
+          -- ALGLIB PROJECT --
+             Copyright 12.10.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void polynomialfit(ref double[] x,
+            ref double[] y,
+            int n,
+            int m,
+            ref int info,
+            ref ratint.barycentricinterpolant p,
+            ref polynomialfitreport rep)
+        {
+            int i = 0;
+            double[] w = new double[0];
+            double[] xc = new double[0];
+            double[] yc = new double[0];
+            int[] dc = new int[0];
+
+            if( n>0 )
+            {
+                w = new double[n];
+                for(i=0; i<=n-1; i++)
+                {
+                    w[i] = 1;
+                }
+            }
+            polynomialfitwc(x, y, ref w, n, xc, yc, ref dc, 0, m, ref info, ref p, ref rep);
+        }
+
+
+        /*************************************************************************
+        Weighted  fitting  by  Chebyshev  polynomial  in  barycentric  form,  with
+        constraints on function values or first derivatives.
+
+        Small regularizing term is used when solving constrained tasks (to improve
+        stability).
+
+        Task is linear, so linear least squares solver is used. Complexity of this
+        computational scheme is O(N*M^2), mostly dominated by least squares solver
+
+        SEE ALSO:
+            PolynomialFit()
+
+        INPUT PARAMETERS:
+            X   -   points, array[0..N-1].
+            Y   -   function values, array[0..N-1].
+            W   -   weights, array[0..N-1]
+                    Each summand in square  sum  of  approximation deviations from
+                    given  values  is  multiplied  by  the square of corresponding
+                    weight. Fill it by 1's if you don't  want  to  solve  weighted
+                    task.
+            N   -   number of points, N>0.
+            XC  -   points where polynomial values/derivatives are constrained,
+                    array[0..K-1].
+            YC  -   values of constraints, array[0..K-1]
+            DC  -   array[0..K-1], types of constraints:
+                    * DC[i]=0   means that P(XC[i])=YC[i]
+                    * DC[i]=1   means that P'(XC[i])=YC[i]
+                    SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
+            K   -   number of constraints, 0<=K<M.
+                    K=0 means no constraints (XC/YC/DC are not used in such cases)
+            M   -   number of basis functions (= polynomial_degree + 1), M>=1
+
+        OUTPUT PARAMETERS:
+            Info-   same format as in LSFitLinearW() subroutine:
+                    * Info>0    task is solved
+                    * Info<=0   an error occured:
+                                -4 means inconvergence of internal SVD
+                                -3 means inconsistent constraints
+                                -1 means another errors in parameters passed
+                                   (N<=0, for example)
+            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.
+
+        SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
+
+        Setting constraints can lead  to undesired  results,  like ill-conditioned
+        behavior, or inconsistency being detected. From the other side,  it allows
+        us to improve quality of the fit. Here we summarize  our  experience  with
+        constrained regression splines:
+        * even simple constraints can be inconsistent, see  Wikipedia  article  on
+          this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
+        * the  greater  is  M (given  fixed  constraints),  the  more chances that
+          constraints will be consistent
+        * in the general case, consistency of constraints is NOT GUARANTEED.
+        * in the one special cases, however, we can  guarantee  consistency.  This
+          case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
+
+        Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
+        can't solve your task without them. Anything beyond  special  cases  given
+        above is not guaranteed and may result in inconsistency.
+
+          -- ALGLIB PROJECT --
+             Copyright 10.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void polynomialfitwc(double[] x,
+            double[] y,
+            ref double[] w,
+            int n,
+            double[] xc,
+            double[] yc,
+            ref int[] dc,
+            int k,
+            int m,
+            ref int info,
+            ref ratint.barycentricinterpolant p,
+            ref polynomialfitreport rep)
+        {
+            double xa = 0;
+            double xb = 0;
+            double sa = 0;
+            double sb = 0;
+            double[] xoriginal = new double[0];
+            double[] yoriginal = new double[0];
+            double[] y2 = new double[0];
+            double[] w2 = new double[0];
+            double[] tmp = new double[0];
+            double[] tmp2 = new double[0];
+            double[] tmpdiff = new double[0];
+            double[] bx = new double[0];
+            double[] by = new double[0];
+            double[] bw = new double[0];
+            double[,] fmatrix = new double[0,0];
+            double[,] cmatrix = new double[0,0];
+            int i = 0;
+            int j = 0;
+            double mx = 0;
+            double decay = 0;
+            double u = 0;
+            double v = 0;
+            double s = 0;
+            int relcnt = 0;
+            lsfit.lsfitreport lrep = new lsfit.lsfitreport();
+            int i_ = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            xc = (double[])xc.Clone();
+            yc = (double[])yc.Clone();
+
+            if( m<1 | n<1 | k<0 | k>=m )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                info = 0;
+                if( dc[i]<0 )
+                {
+                    info = -1;
+                }
+                if( dc[i]>1 )
+                {
+                    info = -1;
+                }
+                if( info<0 )
+                {
+                    return;
+                }
+            }
+            
+            //
+            // weight decay for correct handling of task which becomes
+            // degenerate after constraints are applied
+            //
+            decay = 10000*AP.Math.MachineEpsilon;
+            
+            //
+            // Scale X, Y, XC, YC
+            //
+            lsfit.lsfitscalexy(ref x, ref y, n, ref xc, ref yc, ref dc, k, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref yoriginal);
+            
+            //
+            // 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
+            //
+            y2 = new double[n+m];
+            w2 = new double[n+m];
+            tmp = new double[m];
+            tmpdiff = new double[m];
+            fmatrix = new double[n+m, m];
+            if( k>0 )
+            {
+                cmatrix = new double[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++)
+                {
+                    if( j==0 )
+                    {
+                        tmp[j] = 1;
+                    }
+                    else
+                    {
+                        if( j==1 )
+                        {
+                            tmp[j] = x[i];
+                        }
+                        else
+                        {
+                            tmp[j] = 2*x[i]*tmp[j-1]-tmp[j-2];
+                        }
+                    }
+                }
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    fmatrix[i,i_] = tmp[i_];
+                }
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=m-1; j++)
+                {
+                    if( i==j )
+                    {
+                        fmatrix[n+i,j] = decay;
+                    }
+                    else
+                    {
+                        fmatrix[n+i,j] = 0;
+                    }
+                }
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                y2[i_] = y[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                w2[i_] = w[i_];
+            }
+            mx = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                mx = mx+Math.Abs(w[i]);
+            }
+            mx = mx/n;
+            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++)
+                {
+                    if( j==0 )
+                    {
+                        tmp[j] = 1;
+                        tmpdiff[j] = 0;
+                    }
+                    else
+                    {
+                        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];
+                        }
+                    }
+                }
+                if( dc[i]==0 )
+                {
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        cmatrix[i,i_] = tmp[i_];
+                    }
+                }
+                if( dc[i]==1 )
+                {
+                    for(i_=0; i_<=m-1;i_++)
+                    {
+                        cmatrix[i,i_] = tmpdiff[i_];
+                    }
+                }
+                cmatrix[i,m] = yc[i];
+            }
+            
+            //
+            // Solve constrained task
+            //
+            if( k>0 )
+            {
+                
+                //
+                // solve using regularization
+                //
+                lsfit.lsfitlinearwc(y2, ref w2, ref fmatrix, cmatrix, n+m, m, k, ref info, ref tmp, ref lrep);
+            }
+            else
+            {
+                
+                //
+                // no constraints, no regularization needed
+                //
+                lsfit.lsfitlinearwc(y, ref w, ref fmatrix, cmatrix, n, m, 0, ref info, ref tmp, ref lrep);
+            }
+            if( info<0 )
+            {
+                return;
+            }
+            
+            //
+            // Generate barycentric model and scale it
+            // * BX, BY store barycentric model nodes
+            // * FMatrix is reused (remember - it is at least MxM, what we need)
+            //
+            // Model intialization is done in O(M^2). In principle, it can be
+            // done in O(M*log(M)), but before it we solved task with O(N*M^2)
+            // complexity, so it is only a small amount of total time spent.
+            //
+            bx = new double[m];
+            by = new double[m];
+            bw = new double[m];
+            tmp2 = new double[m];
+            s = 1;
+            for(i=0; i<=m-1; i++)
+            {
+                if( m!=1 )
+                {
+                    u = Math.Cos(Math.PI*i/(m-1));
+                }
+                else
+                {
+                    u = 0;
+                }
+                v = 0;
+                for(j=0; j<=m-1; j++)
+                {
+                    if( j==0 )
+                    {
+                        tmp2[j] = 1;
+                    }
+                    else
+                    {
+                        if( j==1 )
+                        {
+                            tmp2[j] = u;
+                        }
+                        else
+                        {
+                            tmp2[j] = 2*u*tmp2[j-1]-tmp2[j-2];
+                        }
+                    }
+                    v = v+tmp[j]*tmp2[j];
+                }
+                bx[i] = u;
+                by[i] = v;
+                bw[i] = s;
+                if( i==0 | i==m-1 )
+                {
+                    bw[i] = 0.5*bw[i];
+                }
+                s = -s;
+            }
+            ratint.barycentricbuildxyw(ref bx, ref by, ref bw, m, ref p);
+            ratint.barycentriclintransx(ref p, 2/(xb-xa), -((xa+xb)/(xb-xa)));
+            ratint.barycentriclintransy(ref p, sb-sa, sa);
+            
+            //
+            // Scale absolute errors obtained from LSFitLinearW.
+            // Relative error should be calculated separately
+            // (because of shifting/scaling of the task)
+            //
+            rep.taskrcond = lrep.taskrcond;
+            rep.rmserror = lrep.rmserror*(sb-sa);
+            rep.avgerror = lrep.avgerror*(sb-sa);
+            rep.maxerror = lrep.maxerror*(sb-sa);
+            rep.avgrelerror = 0;
+            relcnt = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(yoriginal[i])!=(double)(0) )
+                {
+                    rep.avgrelerror = rep.avgrelerror+Math.Abs(ratint.barycentriccalc(ref p, xoriginal[i])-yoriginal[i])/Math.Abs(yoriginal[i]);
+                    relcnt = relcnt+1;
+                }
+            }
+            if( relcnt!=0 )
+            {
+                rep.avgrelerror = rep.avgrelerror/relcnt;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/psif.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/psif.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/psif.cs	(revision 2645)
@@ -0,0 +1,163 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class psif
+    {
+        /*************************************************************************
+        Psi (digamma) function
+
+                     d      -
+          psi(x)  =  -- ln | (x)
+                     dx
+
+        is the logarithmic derivative of the gamma function.
+        For integer x,
+                          n-1
+                           -
+        psi(n) = -EUL  +   >  1/k.
+                           -
+                          k=1
+
+        This formula is used for 0 < n <= 10.  If x is negative, it
+        is transformed to a positive argument by the reflection
+        formula  psi(1-x) = psi(x) + pi cot(pi x).
+        For general positive x, the argument is made greater than 10
+        using the recurrence  psi(x+1) = psi(x) + 1/x.
+        Then the following asymptotic expansion is applied:
+
+                                  inf.   B
+                                   -      2k
+        psi(x) = log(x) - 1/2x -   >   -------
+                                   -        2k
+                                  k=1   2k x
+
+        where the B2k are Bernoulli numbers.
+
+        ACCURACY:
+           Relative error (except absolute when |psi| < 1):
+        arithmetic   domain     # trials      peak         rms
+           IEEE      0,30        30000       1.3e-15     1.4e-16
+           IEEE      -30,0       40000       1.5e-15     2.2e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double psi(double x)
+        {
+            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;
+
+            negative = 0;
+            nz = 0.0;
+            if( (double)(x)<=(double)(0) )
+            {
+                negative = 1;
+                q = x;
+                p = (int)Math.Floor(q);
+                if( (double)(p)==(double)(q) )
+                {
+                    System.Diagnostics.Debug.Assert(false, "Singularity in Psi(x)");
+                    result = AP.Math.MaxRealNumber;
+                    return result;
+                }
+                nz = q-p;
+                if( (double)(nz)!=(double)(0.5) )
+                {
+                    if( (double)(nz)>(double)(0.5) )
+                    {
+                        p = p+1.0;
+                        nz = q-p;
+                    }
+                    nz = Math.PI/Math.Tan(Math.PI*nz);
+                }
+                else
+                {
+                    nz = 0.0;
+                }
+                x = 1.0-x;
+            }
+            if( (double)(x)<=(double)(10.0) & (double)(x)==(double)((int)Math.Floor(x)) )
+            {
+                y = 0.0;
+                n = (int)Math.Floor(x);
+                for(i=1; i<=n-1; i++)
+                {
+                    w = i;
+                    y = y+1.0/w;
+                }
+                y = y-0.57721566490153286061;
+            }
+            else
+            {
+                s = x;
+                w = 0.0;
+                while( (double)(s)<(double)(10.0) )
+                {
+                    w = w+1.0/s;
+                    s = s+1.0;
+                }
+                if( (double)(s)<(double)(1.0E17) )
+                {
+                    z = 1.0/(s*s);
+                    polv = 8.33333333333333333333E-2;
+                    polv = polv*z-2.10927960927960927961E-2;
+                    polv = polv*z+7.57575757575757575758E-3;
+                    polv = polv*z-4.16666666666666666667E-3;
+                    polv = polv*z+3.96825396825396825397E-3;
+                    polv = polv*z-8.33333333333333333333E-3;
+                    polv = polv*z+8.33333333333333333333E-2;
+                    y = z*polv;
+                }
+                else
+                {
+                    y = 0.0;
+                }
+                y = Math.Log(s)-0.5/s-y-w;
+            }
+            if( negative!=0 )
+            {
+                y = y-nz;
+            }
+            result = y;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/qr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/qr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/qr.cs	(revision 2645)
@@ -0,0 +1,446 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class qr
+    {
+        /*************************************************************************
+        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).
+
+          -- 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.
+             Translation from FORTRAN to pseudocode (AlgoPascal)
+             by Sergey Bochkanov, ALGLIB project, 2005-2007.
+        *************************************************************************/
+        public static void rmatrixqr(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau)
+        {
+            double[] work = new double[0];
+            double[] t = new double[0];
+            int i = 0;
+            int k = 0;
+            int minmn = 0;
+            double tmp = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( m<=0 | n<=0 )
+            {
+                return;
+            }
+            minmn = Math.Min(m, n);
+            work = new double[n-1+1];
+            t = new double[m+1];
+            tau = new double[minmn-1+1];
+            
+            //
+            // Test the input arguments
+            //
+            k = minmn;
+            for(i=0; i<=k-1; i++)
+            {
+                
+                //
+                // Generate elementary reflector H(i) to annihilate A(i+1:m,i)
+                //
+                i1_ = (i) - (1);
+                for(i_=1; i_<=m-i;i_++)
+                {
+                    t[i_] = a[i_+i1_,i];
+                }
+                reflections.generatereflection(ref t, m-i, ref tmp);
+                tau[i] = tmp;
+                i1_ = (1) - (i);
+                for(i_=i; i_<=m-1;i_++)
+                {
+                    a[i_,i] = t[i_+i1_];
+                }
+                t[1] = 1;
+                if( i<n )
+                {
+                    
+                    //
+                    // Apply H(i) to A(i:m-1,i+1:n-1) from the left
+                    //
+                    reflections.applyreflectionfromtheleft(ref a, tau[i], ref t, i, m-1, i+1, n-1, ref work);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixqrunpackq(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau,
+            int qcolumns,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int minmn = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!");
+            if( m<=0 | n<=0 | qcolumns<=0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            minmn = Math.Min(m, n);
+            k = Math.Min(minmn, qcolumns);
+            q = new double[m-1+1, qcolumns-1+1];
+            v = new double[m+1];
+            work = new double[qcolumns-1+1];
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=qcolumns-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=k-1; i>=0; i--)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                i1_ = (i) - (1);
+                for(i_=1; i_<=m-i;i_++)
+                {
+                    v[i_] = a[i_+i1_,i];
+                }
+                v[1] = 1;
+                reflections.applyreflectionfromtheleft(ref q, tau[i], ref v, i, m-1, 0, qcolumns-1, ref work);
+            }
+        }
+
+
+        /*************************************************************************
+        Unpacking of matrix R from the QR decomposition of a matrix A
+
+        Input parameters:
+            A       -   matrices Q and R in compact form.
+                        Output of RMatrixQR subroutine.
+            M       -   number of rows in given matrix A. M>=0.
+            N       -   number of columns in given matrix A. N>=0.
+
+        Output parameters:
+            R       -   matrix R, array[0..M-1, 0..N-1].
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static void rmatrixqrunpackr(ref double[,] a,
+            int m,
+            int n,
+            ref double[,] r)
+        {
+            int i = 0;
+            int k = 0;
+            int i_ = 0;
+
+            if( m<=0 | n<=0 )
+            {
+                return;
+            }
+            k = Math.Min(m, n);
+            r = new double[m-1+1, n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                r[0,i] = 0;
+            }
+            for(i=1; i<=m-1; i++)
+            {
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    r[i,i_] = r[0,i_];
+                }
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                for(i_=i; i_<=n-1;i_++)
+                {
+                    r[i,i_] = a[i,i_];
+                }
+            }
+        }
+
+
+        public static void qrdecomposition(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau)
+        {
+            double[] work = new double[0];
+            double[] t = new double[0];
+            int i = 0;
+            int k = 0;
+            int mmip1 = 0;
+            int minmn = 0;
+            double tmp = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            minmn = Math.Min(m, n);
+            work = new double[n+1];
+            t = new double[m+1];
+            tau = new double[minmn+1];
+            
+            //
+            // Test the input arguments
+            //
+            k = Math.Min(m, n);
+            for(i=1; i<=k; i++)
+            {
+                
+                //
+                // Generate elementary reflector H(i) to annihilate A(i+1:m,i)
+                //
+                mmip1 = m-i+1;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=mmip1;i_++)
+                {
+                    t[i_] = a[i_+i1_,i];
+                }
+                reflections.generatereflection(ref t, mmip1, ref tmp);
+                tau[i] = tmp;
+                i1_ = (1) - (i);
+                for(i_=i; i_<=m;i_++)
+                {
+                    a[i_,i] = t[i_+i1_];
+                }
+                t[1] = 1;
+                if( i<n )
+                {
+                    
+                    //
+                    // Apply H(i) to A(i:m,i+1:n) from the left
+                    //
+                    reflections.applyreflectionfromtheleft(ref a, tau[i], ref t, i, m, i+1, n, ref work);
+                }
+            }
+        }
+
+
+        public static void unpackqfromqr(ref double[,] a,
+            int m,
+            int n,
+            ref double[] tau,
+            int qcolumns,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int minmn = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!");
+            if( m==0 | n==0 | qcolumns==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            minmn = Math.Min(m, n);
+            k = Math.Min(minmn, qcolumns);
+            q = new double[m+1, qcolumns+1];
+            v = new double[m+1];
+            work = new double[qcolumns+1];
+            for(i=1; i<=m; i++)
+            {
+                for(j=1; j<=qcolumns; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            for(i=k; i>=1; i--)
+            {
+                
+                //
+                // Apply H(i)
+                //
+                vm = m-i+1;
+                i1_ = (i) - (1);
+                for(i_=1; i_<=vm;i_++)
+                {
+                    v[i_] = a[i_+i1_,i];
+                }
+                v[1] = 1;
+                reflections.applyreflectionfromtheleft(ref q, tau[i], ref v, i, m, 1, qcolumns, ref work);
+            }
+        }
+
+
+        public static void qrdecompositionunpacked(double[,] a,
+            int m,
+            int n,
+            ref double[,] q,
+            ref double[,] r)
+        {
+            int i = 0;
+            int k = 0;
+            double[] tau = new double[0];
+            double[] work = new double[0];
+            double[] v = new double[0];
+            int i_ = 0;
+
+            a = (double[,])a.Clone();
+
+            k = Math.Min(m, n);
+            if( n<=0 )
+            {
+                return;
+            }
+            work = new double[m+1];
+            v = new double[m+1];
+            q = new double[m+1, m+1];
+            r = new double[m+1, n+1];
+            
+            //
+            // QRDecomposition
+            //
+            qrdecomposition(ref a, m, n, ref tau);
+            
+            //
+            // R
+            //
+            for(i=1; i<=n; i++)
+            {
+                r[1,i] = 0;
+            }
+            for(i=2; i<=m; i++)
+            {
+                for(i_=1; i_<=n;i_++)
+                {
+                    r[i,i_] = r[1,i_];
+                }
+            }
+            for(i=1; i<=k; i++)
+            {
+                for(i_=i; i_<=n;i_++)
+                {
+                    r[i,i_] = a[i,i_];
+                }
+            }
+            
+            //
+            // Q
+            //
+            unpackqfromqr(ref a, m, n, ref tau, m, ref q);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ratint.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ratint.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ratint.cs	(revision 2645)
@@ -0,0 +1,1430 @@
+/*************************************************************************
+Copyright (c) 2007-2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ratint
+    {
+        /*************************************************************************
+        Barycentric interpolant.
+        *************************************************************************/
+        public struct barycentricinterpolant
+        {
+            public int n;
+            public double sy;
+            public double[] x;
+            public double[] y;
+            public double[] w;
+        };
+
+
+        /*************************************************************************
+        Barycentric fitting report:
+            TaskRCond       reciprocal of task's condition number
+            RMSError        RMS error
+            AvgError        average error
+            AvgRelError     average relative error (for non-zero Y[I])
+            MaxError        maximum error
+        *************************************************************************/
+        public struct barycentricfitreport
+        {
+            public double taskrcond;
+            public double dbest;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+            public double maxerror;
+        };
+
+
+
+
+        public const int brcvnum = 10;
+
+
+        /*************************************************************************
+        Rational interpolation using barycentric formula
+
+        F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
+
+        Input parameters:
+            B   -   barycentric interpolant built with one of model building
+                    subroutines.
+            T   -   interpolation point
+
+        Result:
+            barycentric interpolant F(t)
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static double barycentriccalc(ref barycentricinterpolant b,
+            double t)
+        {
+            double result = 0;
+            double s1 = 0;
+            double s2 = 0;
+            double s = 0;
+            double v = 0;
+            int i = 0;
+
+            
+            //
+            // special case: N=1
+            //
+            if( b.n==1 )
+            {
+                result = b.sy*b.y[0];
+                return result;
+            }
+            
+            //
+            // Here we assume that task is normalized, i.e.:
+            // 1. abs(Y[i])<=1
+            // 2. abs(W[i])<=1
+            // 3. X[] is ordered
+            //
+            s = Math.Abs(t-b.x[0]);
+            for(i=0; i<=b.n-1; i++)
+            {
+                v = b.x[i];
+                if( (double)(v)==(double)(t) )
+                {
+                    result = b.sy*b.y[i];
+                    return result;
+                }
+                v = Math.Abs(t-v);
+                if( (double)(v)<(double)(s) )
+                {
+                    s = v;
+                }
+            }
+            s1 = 0;
+            s2 = 0;
+            for(i=0; i<=b.n-1; i++)
+            {
+                v = s/(t-b.x[i]);
+                v = v*b.w[i];
+                s1 = s1+v*b.y[i];
+                s2 = s2+v;
+            }
+            result = b.sy*s1/s2;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Differentiation of barycentric interpolant: first derivative.
+
+        Algorithm used in this subroutine is very robust and should not fail until
+        provided with values too close to MaxRealNumber  (usually  MaxRealNumber/N
+        or greater will overflow).
+
+        INPUT PARAMETERS:
+            B   -   barycentric interpolant built with one of model building
+                    subroutines.
+            T   -   interpolation point
+
+        OUTPUT PARAMETERS:
+            F   -   barycentric interpolant at T
+            DF  -   first derivative
+            
+        NOTE
+
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricdiff1(ref barycentricinterpolant b,
+            double t,
+            ref double f,
+            ref double df)
+        {
+            double v = 0;
+            double vv = 0;
+            int i = 0;
+            int k = 0;
+            double n0 = 0;
+            double n1 = 0;
+            double d0 = 0;
+            double d1 = 0;
+            double s0 = 0;
+            double s1 = 0;
+            double xk = 0;
+            double xi = 0;
+            double xmin = 0;
+            double xmax = 0;
+            double xscale1 = 0;
+            double xoffs1 = 0;
+            double xscale2 = 0;
+            double xoffs2 = 0;
+            double xprev = 0;
+
+            
+            //
+            // special case: N=1
+            //
+            if( b.n==1 )
+            {
+                f = b.sy*b.y[0];
+                df = 0;
+                return;
+            }
+            if( (double)(b.sy)==(double)(0) )
+            {
+                f = 0;
+                df = 0;
+                return;
+            }
+            System.Diagnostics.Debug.Assert((double)(b.sy)>(double)(0), "BarycentricDiff1: internal error");
+            
+            //
+            // 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 = Math.Abs(b.x[0]-t);
+            k = 0;
+            xmin = b.x[0];
+            xmax = b.x[0];
+            for(i=1; i<=b.n-1; i++)
+            {
+                vv = b.x[i];
+                if( (double)(Math.Abs(vv-t))<(double)(v) )
+                {
+                    v = Math.Abs(vv-t);
+                    k = i;
+                }
+                xmin = Math.Min(xmin, vv);
+                xmax = Math.Max(xmax, vv);
+            }
+            
+            //
+            // pivot point found, calculate dNumerator and dDenominator
+            //
+            xscale1 = 1/(xmax-xmin);
+            xoffs1 = -(xmin/(xmax-xmin))+1;
+            xscale2 = 2;
+            xoffs2 = -3;
+            t = t*xscale1+xoffs1;
+            t = t*xscale2+xoffs2;
+            xk = b.x[k];
+            xk = xk*xscale1+xoffs1;
+            xk = xk*xscale2+xoffs2;
+            v = t-xk;
+            n0 = 0;
+            n1 = 0;
+            d0 = 0;
+            d1 = 0;
+            xprev = -2;
+            for(i=0; i<=b.n-1; i++)
+            {
+                xi = b.x[i];
+                xi = xi*xscale1+xoffs1;
+                xi = xi*xscale2+xoffs2;
+                System.Diagnostics.Debug.Assert((double)(xi)>(double)(xprev), "BarycentricDiff1: points are too close!");
+                xprev = xi;
+                if( i!=k )
+                {
+                    vv = AP.Math.Sqr(t-xi);
+                    s0 = (t-xk)/(t-xi);
+                    s1 = (xk-xi)/vv;
+                }
+                else
+                {
+                    s0 = 1;
+                    s1 = 0;
+                }
+                vv = b.w[i]*b.y[i];
+                n0 = n0+s0*vv;
+                n1 = n1+s1*vv;
+                vv = b.w[i];
+                d0 = d0+s0*vv;
+                d1 = d1+s1*vv;
+            }
+            f = b.sy*n0/d0;
+            df = (n1*d0-n0*d1)/AP.Math.Sqr(d0);
+            if( (double)(df)!=(double)(0) )
+            {
+                df = Math.Sign(df)*Math.Exp(Math.Log(Math.Abs(df))+Math.Log(b.sy)+Math.Log(xscale1)+Math.Log(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.
+
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricdiff2(ref barycentricinterpolant b,
+            double t,
+            ref double f,
+            ref double df,
+            ref double d2f)
+        {
+            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;
+
+            f = 0;
+            df = 0;
+            d2f = 0;
+            
+            //
+            // special case: N=1
+            //
+            if( b.n==1 )
+            {
+                f = b.sy*b.y[0];
+                df = 0;
+                d2f = 0;
+                return;
+            }
+            if( (double)(b.sy)==(double)(0) )
+            {
+                f = 0;
+                df = 0;
+                d2f = 0;
+                return;
+            }
+            System.Diagnostics.Debug.Assert((double)(b.sy)>(double)(0), "BarycentricDiff: internal error");
+            
+            //
+            // 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 = Math.Abs(b.x[0]-t);
+            k = 0;
+            for(i=1; i<=b.n-1; i++)
+            {
+                vv = b.x[i];
+                if( (double)(Math.Abs(vv-t))<(double)(v) )
+                {
+                    v = Math.Abs(vv-t);
+                    k = i;
+                }
+            }
+            
+            //
+            // pivot point found, calculate dNumerator and dDenominator
+            //
+            xk = b.x[k];
+            v = t-xk;
+            n0 = 0;
+            n1 = 0;
+            n2 = 0;
+            d0 = 0;
+            d1 = 0;
+            d2 = 0;
+            for(i=0; i<=b.n-1; i++)
+            {
+                if( i!=k )
+                {
+                    xi = b.x[i];
+                    vv = AP.Math.Sqr(t-xi);
+                    s0 = (t-xk)/(t-xi);
+                    s1 = (xk-xi)/vv;
+                    s2 = -(2*(xk-xi)/(vv*(t-xi)));
+                }
+                else
+                {
+                    s0 = 1;
+                    s1 = 0;
+                    s2 = 0;
+                }
+                vv = b.w[i]*b.y[i];
+                n0 = n0+s0*vv;
+                n1 = n1+s1*vv;
+                n2 = n2+s2*vv;
+                vv = b.w[i];
+                d0 = d0+s0*vv;
+                d1 = d1+s1*vv;
+                d2 = d2+s2*vv;
+            }
+            f = b.sy*n0/d0;
+            df = b.sy*(n1*d0-n0*d1)/AP.Math.Sqr(d0);
+            d2f = b.sy*((n2*d0-n0*d2)*AP.Math.Sqr(d0)-(n1*d0-n0*d1)*2*d0*d1)/AP.Math.Sqr(AP.Math.Sqr(d0));
+        }
+
+
+        /*************************************************************************
+        This subroutine performs linear transformation of the argument.
+
+        INPUT PARAMETERS:
+            B       -   rational interpolant in barycentric form
+            CA, CB  -   transformation coefficients: x = CA*t + CB
+
+        OUTPUT PARAMETERS:
+            B       -   transformed interpolant with X replaced by T
+
+          -- ALGLIB PROJECT --
+             Copyright 19.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentriclintransx(ref barycentricinterpolant b,
+            double ca,
+            double cb)
+        {
+            int i = 0;
+            int j = 0;
+            double v = 0;
+
+            
+            //
+            // special case, replace by constant F(CB)
+            //
+            if( (double)(ca)==(double)(0) )
+            {
+                b.sy = barycentriccalc(ref b, cb);
+                v = 1;
+                for(i=0; i<=b.n-1; i++)
+                {
+                    b.y[i] = 1;
+                    b.w[i] = v;
+                    v = -v;
+                }
+                return;
+            }
+            
+            //
+            // general case: CA<>0
+            //
+            for(i=0; i<=b.n-1; i++)
+            {
+                b.x[i] = (b.x[i]-cb)/ca;
+            }
+            if( (double)(ca)<(double)(0) )
+            {
+                for(i=0; i<=b.n-1; i++)
+                {
+                    if( i<b.n-1-i )
+                    {
+                        j = b.n-1-i;
+                        v = b.x[i];
+                        b.x[i] = b.x[j];
+                        b.x[j] = v;
+                        v = b.y[i];
+                        b.y[i] = b.y[j];
+                        b.y[j] = v;
+                        v = b.w[i];
+                        b.w[i] = b.w[j];
+                        b.w[j] = v;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        This  subroutine   performs   linear  transformation  of  the  barycentric
+        interpolant.
+
+        INPUT PARAMETERS:
+            B       -   rational interpolant in barycentric form
+            CA, CB  -   transformation coefficients: B2(x) = CA*B(x) + CB
+
+        OUTPUT PARAMETERS:
+            B       -   transformed interpolant
+
+          -- ALGLIB PROJECT --
+             Copyright 19.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentriclintransy(ref barycentricinterpolant b,
+            double ca,
+            double cb)
+        {
+            int i = 0;
+            double v = 0;
+            int i_ = 0;
+
+            for(i=0; i<=b.n-1; i++)
+            {
+                b.y[i] = ca*b.sy*b.y[i]+cb;
+            }
+            b.sy = 0;
+            for(i=0; i<=b.n-1; i++)
+            {
+                b.sy = Math.Max(b.sy, Math.Abs(b.y[i]));
+            }
+            if( (double)(b.sy)>(double)(0) )
+            {
+                v = 1/b.sy;
+                for(i_=0; i_<=b.n-1;i_++)
+                {
+                    b.y[i_] = v*b.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]
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricunpack(ref barycentricinterpolant b,
+            ref int n,
+            ref double[] x,
+            ref double[] y,
+            ref double[] w)
+        {
+            double v = 0;
+            int i_ = 0;
+
+            n = b.n;
+            x = new double[n];
+            y = new double[n];
+            w = new double[n];
+            v = b.sy;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                x[i_] = b.x[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                y[i_] = v*b.y[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                w[i_] = b.w[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of the barycentric interpolant
+
+        INPUT PARAMETERS:
+            B   -   barycentric interpolant
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which contains interpolant,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricserialize(ref barycentricinterpolant b,
+            ref double[] ra,
+            ref int ralen)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            ralen = 2+2+3*b.n;
+            ra = new double[ralen];
+            ra[0] = ralen;
+            ra[1] = brcvnum;
+            ra[2] = b.n;
+            ra[3] = b.sy;
+            i1_ = (0) - (4);
+            for(i_=4; i_<=4+b.n-1;i_++)
+            {
+                ra[i_] = b.x[i_+i1_];
+            }
+            i1_ = (0) - (4+b.n);
+            for(i_=4+b.n; i_<=4+2*b.n-1;i_++)
+            {
+                ra[i_] = b.y[i_+i1_];
+            }
+            i1_ = (0) - (4+2*b.n);
+            for(i_=4+2*b.n; i_<=4+3*b.n-1;i_++)
+            {
+                ra[i_] = b.w[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Unserialization of the barycentric interpolant
+
+        INPUT PARAMETERS:
+            RA  -   array of real numbers which contains interpolant,
+
+        OUTPUT PARAMETERS:
+            B   -   barycentric interpolant
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricunserialize(ref double[] ra,
+            ref barycentricinterpolant b)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[1])==brcvnum, "BarycentricUnserialize: corrupted array!");
+            b.n = (int)Math.Round(ra[2]);
+            b.sy = ra[3];
+            b.x = new double[b.n];
+            b.y = new double[b.n];
+            b.w = new double[b.n];
+            i1_ = (4) - (0);
+            for(i_=0; i_<=b.n-1;i_++)
+            {
+                b.x[i_] = ra[i_+i1_];
+            }
+            i1_ = (4+b.n) - (0);
+            for(i_=0; i_<=b.n-1;i_++)
+            {
+                b.y[i_] = ra[i_+i1_];
+            }
+            i1_ = (4+2*b.n) - (0);
+            for(i_=0; i_<=b.n-1;i_++)
+            {
+                b.w[i_] = ra[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Copying of the barycentric interpolant
+
+        INPUT PARAMETERS:
+            B   -   barycentric interpolant
+
+        OUTPUT PARAMETERS:
+            B2  -   copy(B1)
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentriccopy(ref barycentricinterpolant b,
+            ref barycentricinterpolant b2)
+        {
+            int i_ = 0;
+
+            b2.n = b.n;
+            b2.sy = b.sy;
+            b2.x = new double[b2.n];
+            b2.y = new double[b2.n];
+            b2.w = new double[b2.n];
+            for(i_=0; i_<=b2.n-1;i_++)
+            {
+                b2.x[i_] = b.x[i_];
+            }
+            for(i_=0; i_<=b2.n-1;i_++)
+            {
+                b2.y[i_] = b.y[i_];
+            }
+            for(i_=0; i_<=b2.n-1;i_++)
+            {
+                b2.w[i_] = b.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)
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricbuildxyw(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            int n,
+            ref barycentricinterpolant b)
+        {
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "BarycentricBuildXYW: incorrect N!");
+            
+            //
+            // fill X/Y/W
+            //
+            b.x = new double[n];
+            b.y = new double[n];
+            b.w = new double[n];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                b.x[i_] = x[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                b.y[i_] = y[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                b.w[i_] = w[i_];
+            }
+            b.n = n;
+            
+            //
+            // Normalize
+            //
+            barycentricnormalize(ref b);
+        }
+
+
+        /*************************************************************************
+        Rational interpolant without poles
+
+        The subroutine constructs the rational interpolating function without real
+        poles  (see  'Barycentric rational interpolation with no  poles  and  high
+        rates of approximation', Michael S. Floater. and  Kai  Hormann,  for  more
+        information on this subject).
+
+        Input parameters:
+            X   -   interpolation nodes, array[0..N-1].
+            Y   -   function values, array[0..N-1].
+            N   -   number of nodes, N>0.
+            D   -   order of the interpolation scheme, 0 <= D <= N-1.
+                    D<0 will cause an error.
+                    D>=N it will be replaced with D=N-1.
+                    if you don't know what D to choose, use small value about 3-5.
+
+        Output parameters:
+            B   -   barycentric interpolant.
+
+        Note:
+            this algorithm always succeeds and calculates the weights  with  close
+            to machine precision.
+
+          -- ALGLIB PROJECT --
+             Copyright 17.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricbuildfloaterhormann(ref double[] x,
+            ref double[] y,
+            int n,
+            int d,
+            ref barycentricinterpolant b)
+        {
+            double s0 = 0;
+            double s = 0;
+            double v = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int[] perm = new int[0];
+            double[] wtemp = new double[0];
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "BarycentricFloaterHormann: N<=0!");
+            System.Diagnostics.Debug.Assert(d>=0, "BarycentricFloaterHormann: incorrect D!");
+            
+            //
+            // Prepare
+            //
+            if( d>n-1 )
+            {
+                d = n-1;
+            }
+            b.n = n;
+            
+            //
+            // special case: N=1
+            //
+            if( n==1 )
+            {
+                b.x = new double[n];
+                b.y = new double[n];
+                b.w = new double[n];
+                b.x[0] = x[0];
+                b.y[0] = y[0];
+                b.w[0] = 1;
+                barycentricnormalize(ref b);
+                return;
+            }
+            
+            //
+            // Fill X/Y
+            //
+            b.x = new double[n];
+            b.y = new double[n];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                b.x[i_] = x[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                b.y[i_] = y[i_];
+            }
+            tsort.tagsortfastr(ref b.x, ref b.y, n);
+            
+            //
+            // Calculate Wk
+            //
+            b.w = new double[n];
+            s0 = 1;
+            for(k=1; k<=d; k++)
+            {
+                s0 = -s0;
+            }
+            for(k=0; k<=n-1; k++)
+            {
+                
+                //
+                // Wk
+                //
+                s = 0;
+                for(i=Math.Max(k-d, 0); i<=Math.Min(k, n-1-d); i++)
+                {
+                    v = 1;
+                    for(j=i; j<=i+d; j++)
+                    {
+                        if( j!=k )
+                        {
+                            v = v/Math.Abs(b.x[k]-b.x[j]);
+                        }
+                    }
+                    s = s+v;
+                }
+                b.w[k] = s0*s;
+                
+                //
+                // Next S0
+                //
+                s0 = -s0;
+            }
+            
+            //
+            // Normalize
+            //
+            barycentricnormalize(ref b);
+        }
+
+
+        /*************************************************************************
+        Weghted rational least  squares  fitting  using  Floater-Hormann  rational
+        functions  with  optimal  D  chosen  from  [0,9],  with  constraints   and
+        individual weights.
+
+        Equidistant grid with M+1 node on [min(x),max(x)]  is  used to build basis
+        functions. Different values of D are tried, optimal D (least WEIGHTED root
+        mean square error) is chosen.  Task  is  linear,  so  linear least squares
+        solver  is  used.  Complexity  of  this  computational  scheme is O(N*M^2)
+        (mostly dominated by the least squares solver).
+
+        SEE ALSO
+        * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual
+          weights and constraints.
+
+        INPUT PARAMETERS:
+            X   -   points, array[0..N-1].
+            Y   -   function values, array[0..N-1].
+            W   -   weights, array[0..N-1]
+                    Each summand in square  sum  of  approximation deviations from
+                    given  values  is  multiplied  by  the square of corresponding
+                    weight. Fill it by 1's if you don't  want  to  solve  weighted
+                    task.
+            N   -   number of points, N>0.
+            XC  -   points where function values/derivatives are constrained,
+                    array[0..K-1].
+            YC  -   values of constraints, array[0..K-1]
+            DC  -   array[0..K-1], types of constraints:
+                    * DC[i]=0   means that S(XC[i])=YC[i]
+                    * DC[i]=1   means that S'(XC[i])=YC[i]
+                    SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
+            K   -   number of constraints, 0<=K<M.
+                    K=0 means no constraints (XC/YC/DC are not used in such cases)
+            M   -   number of basis functions ( = number_of_nodes), M>=2.
+
+        OUTPUT PARAMETERS:
+            Info-   same format as in LSFitLinearWC() subroutine.
+                    * Info>0    task is solved
+                    * Info<=0   an error occured:
+                                -4 means inconvergence of internal SVD
+                                -3 means inconsistent constraints
+                                -1 means another errors in parameters passed
+                                   (N<=0, for example)
+            B   -   barycentric interpolant.
+            Rep -   report, same format as in LSFitLinearWC() subroutine.
+                    Following fields are set:
+                    * DBest         best value of the D parameter
+                    * RMSError      rms error on the (X,Y).
+                    * AvgError      average error on the (X,Y).
+                    * AvgRelError   average relative error on the non-zero Y
+                    * MaxError      maximum error
+                                    NON-WEIGHTED ERRORS ARE CALCULATED
+
+        IMPORTANT:
+            this subroitine doesn't calculate task's condition number for K<>0.
+
+        SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
+
+        Setting constraints can lead  to undesired  results,  like ill-conditioned
+        behavior, or inconsistency being detected. From the other side,  it allows
+        us to improve quality of the fit. Here we summarize  our  experience  with
+        constrained barycentric interpolants:
+        * excessive  constraints  can  be  inconsistent.   Floater-Hormann   basis
+          functions aren't as flexible as splines (although they are very smooth).
+        * the more evenly constraints are spread across [min(x),max(x)],  the more
+          chances that they will be consistent
+        * the  greater  is  M (given  fixed  constraints),  the  more chances that
+          constraints will be consistent
+        * in the general case, consistency of constraints IS NOT GUARANTEED.
+        * in the several special cases, however, we CAN guarantee consistency.
+        * one of this cases is constraints on the function  VALUES at the interval
+          boundaries. Note that consustency of the  constraints  on  the  function
+          DERIVATIVES is NOT guaranteed (you can use in such cases  cubic  splines
+          which are more flexible).
+        * another  special  case  is ONE constraint on the function value (OR, but
+          not AND, derivative) anywhere in the interval
+
+        Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
+        can't solve your task without them. Anything beyond  special  cases  given
+        above is not guaranteed and may result in inconsistency.
+
+          -- ALGLIB PROJECT --
+             Copyright 18.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricfitfloaterhormannwc(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            int n,
+            ref double[] xc,
+            ref double[] yc,
+            ref int[] dc,
+            int k,
+            int m,
+            ref int info,
+            ref barycentricinterpolant b,
+            ref barycentricfitreport rep)
+        {
+            int d = 0;
+            int i = 0;
+            double wrmscur = 0;
+            double wrmsbest = 0;
+            barycentricinterpolant locb = new barycentricinterpolant();
+            barycentricfitreport locrep = new barycentricfitreport();
+            int locinfo = 0;
+
+            if( n<1 | m<2 | k<0 | k>=m )
+            {
+                info = -1;
+                return;
+            }
+            
+            //
+            // Find optimal D
+            //
+            // Info is -3 by default (degenerate constraints).
+            // If LocInfo will always be equal to -3, Info will remain equal to -3.
+            // If at least once LocInfo will be -4, Info will be -4.
+            //
+            wrmsbest = AP.Math.MaxRealNumber;
+            rep.dbest = -1;
+            info = -3;
+            for(d=0; d<=Math.Min(9, n-1); d++)
+            {
+                barycentricfitwcfixedd(x, y, ref w, n, xc, yc, ref dc, k, m, d, ref locinfo, ref locb, ref locrep);
+                System.Diagnostics.Debug.Assert(locinfo==-4 | locinfo==-3 | locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!");
+                if( locinfo>0 )
+                {
+                    
+                    //
+                    // Calculate weghted RMS
+                    //
+                    wrmscur = 0;
+                    for(i=0; i<=n-1; i++)
+                    {
+                        wrmscur = wrmscur+AP.Math.Sqr(w[i]*(y[i]-barycentriccalc(ref locb, x[i])));
+                    }
+                    wrmscur = Math.Sqrt(wrmscur/n);
+                    if( (double)(wrmscur)<(double)(wrmsbest) | (double)(rep.dbest)<(double)(0) )
+                    {
+                        barycentriccopy(ref locb, ref b);
+                        rep.dbest = d;
+                        info = 1;
+                        rep.rmserror = locrep.rmserror;
+                        rep.avgerror = locrep.avgerror;
+                        rep.avgrelerror = locrep.avgrelerror;
+                        rep.maxerror = locrep.maxerror;
+                        rep.taskrcond = locrep.taskrcond;
+                        wrmsbest = wrmscur;
+                    }
+                }
+                else
+                {
+                    if( locinfo!=-3 & info<0 )
+                    {
+                        info = locinfo;
+                    }
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Rational least squares fitting, without weights and constraints.
+
+        See BarycentricFitFloaterHormannWC() for more information.
+
+          -- ALGLIB PROJECT --
+             Copyright 18.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void barycentricfitfloaterhormann(ref double[] x,
+            ref double[] y,
+            int n,
+            int m,
+            ref int info,
+            ref barycentricinterpolant b,
+            ref barycentricfitreport rep)
+        {
+            double[] w = new double[0];
+            double[] xc = new double[0];
+            double[] yc = new double[0];
+            int[] dc = new int[0];
+            int i = 0;
+
+            if( n<1 )
+            {
+                info = -1;
+                return;
+            }
+            w = new double[n];
+            for(i=0; i<=n-1; i++)
+            {
+                w[i] = 1;
+            }
+            barycentricfitfloaterhormannwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref b, ref rep);
+        }
+
+
+        /*************************************************************************
+        Normalization of barycentric interpolant.
+        Internal subroutine
+        *************************************************************************/
+        private static void barycentricnormalize(ref barycentricinterpolant b)
+        {
+            int[] p1 = new int[0];
+            int[] p2 = new int[0];
+            int i = 0;
+            int j = 0;
+            int j2 = 0;
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            // Normalize task: |Y|<=1, |W|<=1, sort X[]
+            //
+            b.sy = 0;
+            for(i=0; i<=b.n-1; i++)
+            {
+                b.sy = Math.Max(b.sy, Math.Abs(b.y[i]));
+            }
+            if( (double)(b.sy)>(double)(0) & (double)(Math.Abs(b.sy-1))>(double)(10*AP.Math.MachineEpsilon) )
+            {
+                v = 1/b.sy;
+                for(i_=0; i_<=b.n-1;i_++)
+                {
+                    b.y[i_] = v*b.y[i_];
+                }
+            }
+            v = 0;
+            for(i=0; i<=b.n-1; i++)
+            {
+                v = Math.Max(v, Math.Abs(b.w[i]));
+            }
+            if( (double)(v)>(double)(0) & (double)(Math.Abs(v-1))>(double)(10*AP.Math.MachineEpsilon) )
+            {
+                v = 1/v;
+                for(i_=0; i_<=b.n-1;i_++)
+                {
+                    b.w[i_] = v*b.w[i_];
+                }
+            }
+            for(i=0; i<=b.n-2; i++)
+            {
+                if( (double)(b.x[i+1])<(double)(b.x[i]) )
+                {
+                    tsort.tagsort(ref b.x, b.n, ref p1, ref p2);
+                    for(j=0; j<=b.n-1; j++)
+                    {
+                        j2 = p2[j];
+                        v = b.y[j];
+                        b.y[j] = b.y[j2];
+                        b.y[j2] = v;
+                        v = b.w[j];
+                        b.w[j] = b.w[j2];
+                        b.w[j2] = v;
+                    }
+                    break;
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine, calculates barycentric basis functions.
+        Used for efficient simultaneous calculation of N basis functions.
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void barycentriccalcbasis(ref barycentricinterpolant b,
+            double t,
+            ref double[] y)
+        {
+            double s2 = 0;
+            double s = 0;
+            double v = 0;
+            int i = 0;
+            int j = 0;
+            int i_ = 0;
+
+            
+            //
+            // special case: N=1
+            //
+            if( b.n==1 )
+            {
+                y[0] = 1;
+                return;
+            }
+            
+            //
+            // Here we assume that task is normalized, i.e.:
+            // 1. abs(Y[i])<=1
+            // 2. abs(W[i])<=1
+            // 3. X[] is ordered
+            //
+            // First, we decide: should we use "safe" formula (guarded
+            // against overflow) or fast one?
+            //
+            s = Math.Abs(t-b.x[0]);
+            for(i=0; i<=b.n-1; i++)
+            {
+                v = b.x[i];
+                if( (double)(v)==(double)(t) )
+                {
+                    for(j=0; j<=b.n-1; j++)
+                    {
+                        y[j] = 0;
+                    }
+                    y[i] = 1;
+                    return;
+                }
+                v = Math.Abs(t-v);
+                if( (double)(v)<(double)(s) )
+                {
+                    s = v;
+                }
+            }
+            s2 = 0;
+            for(i=0; i<=b.n-1; i++)
+            {
+                v = s/(t-b.x[i]);
+                v = v*b.w[i];
+                y[i] = v;
+                s2 = s2+v;
+            }
+            v = 1/s2;
+            for(i_=0; i_<=b.n-1;i_++)
+            {
+                y[i_] = v*y[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Internal Floater-Hormann fitting subroutine for fixed D
+        *************************************************************************/
+        private static void barycentricfitwcfixedd(double[] x,
+            double[] y,
+            ref double[] w,
+            int n,
+            double[] xc,
+            double[] yc,
+            ref int[] dc,
+            int k,
+            int m,
+            int d,
+            ref int info,
+            ref barycentricinterpolant b,
+            ref barycentricfitreport rep)
+        {
+            double[,] fmatrix = new double[0,0];
+            double[,] cmatrix = new double[0,0];
+            double[] y2 = new double[0];
+            double[] w2 = new double[0];
+            double[] sx = new double[0];
+            double[] sy = new double[0];
+            double[] sbf = new double[0];
+            double[] xoriginal = new double[0];
+            double[] yoriginal = new double[0];
+            double[] tmp = new double[0];
+            lsfit.lsfitreport lrep = new lsfit.lsfitreport();
+            double v = 0;
+            double v0 = 0;
+            double v1 = 0;
+            double v2 = 0;
+            double mx = 0;
+            barycentricinterpolant b2 = new barycentricinterpolant();
+            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;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            xc = (double[])xc.Clone();
+            yc = (double[])yc.Clone();
+
+            if( n<1 | m<2 | k<0 | k>=m )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                info = 0;
+                if( dc[i]<0 )
+                {
+                    info = -1;
+                }
+                if( dc[i]>1 )
+                {
+                    info = -1;
+                }
+                if( info<0 )
+                {
+                    return;
+                }
+            }
+            
+            //
+            // weight decay for correct handling of task which becomes
+            // degenerate after constraints are applied
+            //
+            decay = 10000*AP.Math.MachineEpsilon;
+            
+            //
+            // Scale X, Y, XC, YC
+            //
+            lsfit.lsfitscalexy(ref x, ref y, n, ref xc, ref yc, ref dc, k, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref yoriginal);
+            
+            //
+            // allocate space, initialize:
+            // * FMatrix-   values of basis functions at X[]
+            // * CMatrix-   values (derivatives) of basis functions at XC[]
+            //
+            y2 = new double[n+m];
+            w2 = new double[n+m];
+            fmatrix = new double[n+m, m];
+            if( k>0 )
+            {
+                cmatrix = new double[k, m+1];
+            }
+            y2 = new double[n+m];
+            w2 = new double[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
+            //
+            sx = new double[m];
+            sy = new double[m];
+            sbf = new double[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;
+            }
+            barycentricbuildfloaterhormann(ref sx, ref sy, m, d, ref b2);
+            mx = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                barycentriccalcbasis(ref b2, x[i], ref sbf);
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    fmatrix[i,i_] = sbf[i_];
+                }
+                y2[i] = y[i];
+                w2[i] = w[i];
+                mx = mx+Math.Abs(w[i])/n;
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=m-1; j++)
+                {
+                    if( i==j )
+                    {
+                        fmatrix[n+i,j] = decay;
+                    }
+                    else
+                    {
+                        fmatrix[n+i,j] = 0;
+                    }
+                }
+                y2[n+i] = 0;
+                w2[n+i] = mx;
+            }
+            if( k>0 )
+            {
+                for(j=0; j<=m-1; j++)
+                {
+                    for(i=0; i<=m-1; i++)
+                    {
+                        sy[i] = 0;
+                    }
+                    sy[j] = 1;
+                    barycentricbuildfloaterhormann(ref sx, ref sy, m, d, ref b2);
+                    for(i=0; i<=k-1; i++)
+                    {
+                        System.Diagnostics.Debug.Assert(dc[i]>=0 & dc[i]<=1, "BarycentricFit: internal error!");
+                        barycentricdiff1(ref b2, xc[i], ref v0, ref v1);
+                        if( dc[i]==0 )
+                        {
+                            cmatrix[i,j] = v0;
+                        }
+                        if( dc[i]==1 )
+                        {
+                            cmatrix[i,j] = v1;
+                        }
+                    }
+                }
+                for(i=0; i<=k-1; i++)
+                {
+                    cmatrix[i,m] = yc[i];
+                }
+            }
+            
+            //
+            // Solve constrained task
+            //
+            if( k>0 )
+            {
+                
+                //
+                // solve using regularization
+                //
+                lsfit.lsfitlinearwc(y2, ref w2, ref fmatrix, cmatrix, n+m, m, k, ref info, ref tmp, ref lrep);
+            }
+            else
+            {
+                
+                //
+                // no constraints, no regularization needed
+                //
+                lsfit.lsfitlinearwc(y, ref w, ref fmatrix, cmatrix, n, m, k, ref info, ref tmp, ref lrep);
+            }
+            if( info<0 )
+            {
+                return;
+            }
+            
+            //
+            // Generate interpolant and scale it
+            //
+            for(i_=0; i_<=m-1;i_++)
+            {
+                sy[i_] = tmp[i_];
+            }
+            barycentricbuildfloaterhormann(ref sx, ref sy, m, d, ref b);
+            barycentriclintransx(ref b, 2/(xb-xa), -((xa+xb)/(xb-xa)));
+            barycentriclintransy(ref b, sb-sa, sa);
+            
+            //
+            // Scale absolute errors obtained from LSFitLinearW.
+            // Relative error should be calculated separately
+            // (because of shifting/scaling of the task)
+            //
+            rep.taskrcond = lrep.taskrcond;
+            rep.rmserror = lrep.rmserror*(sb-sa);
+            rep.avgerror = lrep.avgerror*(sb-sa);
+            rep.maxerror = lrep.maxerror*(sb-sa);
+            rep.avgrelerror = 0;
+            relcnt = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(yoriginal[i])!=(double)(0) )
+                {
+                    rep.avgrelerror = rep.avgrelerror+Math.Abs(barycentriccalc(ref b, xoriginal[i])-yoriginal[i])/Math.Abs(yoriginal[i]);
+                    relcnt = relcnt+1;
+                }
+            }
+            if( relcnt!=0 )
+            {
+                rep.avgrelerror = rep.avgrelerror/relcnt;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ratinterpolation.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ratinterpolation.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ratinterpolation.cs	(revision 2645)
@@ -0,0 +1,130 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ratinterpolation
+    {
+        /*************************************************************************
+        Rational barycentric interpolation without poles
+
+        The subroutine constructs the rational interpolating function without real
+        poles. It should be noted that the barycentric weights of the  interpolant
+        constructed are independent of the values of the given function.
+
+        Input parameters:
+            X   -   interpolation nodes, array[0..N-1].
+            N   -   number of nodes, N>0.
+            D   -   order of the interpolation scheme, 0 <= D <= N-1.
+
+        Output parameters:
+            W   -   array of the barycentric weights which  can  be  used  in  the
+                    BarycentricInterpolate subroutine. Array[0..N-1]
+
+        Note:
+            this algorithm always succeeds and calculates the weights  with  close
+            to machine precision.
+
+          -- ALGLIB PROJECT --
+             Copyright 17.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void buildfloaterhormannrationalinterpolant(double[] x,
+            int n,
+            int d,
+            ref double[] w)
+        {
+            double s0 = 0;
+            double s = 0;
+            double v = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int[] perm = new int[0];
+            double[] wtemp = new double[0];
+            int i_ = 0;
+
+            x = (double[])x.Clone();
+
+            System.Diagnostics.Debug.Assert(n>0, "BuildRationalInterpolantWithoutPoles: N<=0!");
+            System.Diagnostics.Debug.Assert(d>=0 & d<=n, "BuildRationalInterpolantWithoutPoles: incorrect D!");
+            
+            //
+            // Prepare
+            //
+            w = new double[n-1+1];
+            s0 = 1;
+            for(k=1; k<=d; k++)
+            {
+                s0 = -s0;
+            }
+            perm = new int[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                perm[i] = i;
+            }
+            tsort.tagsortfasti(ref x, ref perm, n);
+            
+            //
+            // Calculate Wk
+            //
+            for(k=0; k<=n-1; k++)
+            {
+                
+                //
+                // Wk
+                //
+                s = 0;
+                for(i=Math.Max(k-d, 0); i<=Math.Min(k, n-1-d); i++)
+                {
+                    v = 1;
+                    for(j=i; j<=i+d; j++)
+                    {
+                        if( j!=k )
+                        {
+                            v = v/Math.Abs(x[k]-x[j]);
+                        }
+                    }
+                    s = s+v;
+                }
+                w[k] = s0*s;
+                
+                //
+                // Next S0
+                //
+                s0 = -s0;
+            }
+            
+            //
+            // Reorder W
+            //
+            wtemp = new double[n-1+1];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                wtemp[i_] = w[i_];
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                w[perm[i]] = wtemp[i];
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/rcond.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/rcond.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/rcond.cs	(revision 2645)
@@ -0,0 +1,730 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class rcond
+    {
+        /*************************************************************************
+        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))
+        *************************************************************************/
+        public static double rmatrixrcond1(ref double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            double[,] a1 = new double[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "RMatrixRCond1: N<1!");
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = a[i-1,i_+i1_];
+                }
+            }
+            result = rcond1(a1, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Estimate of the condition number of a matrix given by its LU decomposition (1-norm)
+
+        The algorithm calculates a lower bound of the condition number. In this case,
+        the algorithm does not return a lower bound of the condition number, but an
+        inverse number (to avoid an overflow in case of a singular matrix).
+
+        Input parameters:
+            LUDcmp      -   LU decomposition of a matrix in compact form. Output of
+                            the RMatrixLU subroutine.
+            N           -   size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double rmatrixlurcond1(ref double[,] ludcmp,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            double[,] a1 = new double[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "RMatrixLURCond1: N<1!");
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = ludcmp[i-1,i_+i1_];
+                }
+            }
+            result = rcond1lu(ref a1, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Estimate of a matrix condition number (infinity-norm).
+
+        The algorithm calculates a lower bound of the condition number. In this case,
+        the algorithm does not return a lower bound of the condition number, but an
+        inverse number (to avoid an overflow in case of a singular matrix).
+
+        Input parameters:
+            A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
+            N   -   size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double rmatrixrcondinf(ref double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            double[,] a1 = new double[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "RMatrixRCondInf: N<1!");
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = a[i-1,i_+i1_];
+                }
+            }
+            result = rcondinf(a1, n);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Estimate of the condition number of a matrix given by its LU decomposition
+        (infinity norm).
+
+        The algorithm calculates a lower bound of the condition number. In this case,
+        the algorithm does not return a lower bound of the condition number, but an
+        inverse number (to avoid an overflow in case of a singular matrix).
+
+        Input parameters:
+            LUDcmp  -   LU decomposition of a matrix in compact form. Output of
+                        the RMatrixLU subroutine.
+            N       -   size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double rmatrixlurcondinf(ref double[,] ludcmp,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            double[,] a1 = new double[0,0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "RMatrixLURCondInf: N<1!");
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = ludcmp[i-1,i_+i1_];
+                }
+            }
+            result = rcondinflu(ref a1, n);
+            return result;
+        }
+
+
+        public static double rcond1(double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            nrm = 0;
+            for(j=1; j<=n; j++)
+            {
+                v = 0;
+                for(i=1; i<=n; i++)
+                {
+                    v = v+Math.Abs(a[i,j]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            lu.ludecomposition(ref a, n, n, ref pivots);
+            internalestimatercondlu(ref a, n, true, true, nrm, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double rcond1lu(ref double[,] ludcmp,
+            int n)
+        {
+            double result = 0;
+            double v = 0;
+
+            internalestimatercondlu(ref ludcmp, n, true, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double rcondinf(double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            nrm = 0;
+            for(i=1; i<=n; i++)
+            {
+                v = 0;
+                for(j=1; j<=n; j++)
+                {
+                    v = v+Math.Abs(a[i,j]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            lu.ludecomposition(ref a, n, n, ref pivots);
+            internalestimatercondlu(ref a, n, false, true, nrm, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double rcondinflu(ref double[,] ludcmp,
+            int n)
+        {
+            double result = 0;
+            double v = 0;
+
+            internalestimatercondlu(ref ludcmp, n, false, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        private static void internalestimatercondlu(ref double[,] ludcmp,
+            int n,
+            bool onenorm,
+            bool isanormprovided,
+            double anorm,
+            ref double rc)
+        {
+            double[] work0 = new double[0];
+            double[] work1 = new double[0];
+            double[] work2 = new double[0];
+            double[] work3 = new double[0];
+            int[] iwork = new int[0];
+            double v = 0;
+            bool normin = new bool();
+            int i = 0;
+            int im1 = 0;
+            int ip1 = 0;
+            int ix = 0;
+            int kase = 0;
+            int kase1 = 0;
+            double ainvnm = 0;
+            double ascale = 0;
+            double sl = 0;
+            double smlnum = 0;
+            double su = 0;
+            bool mupper = new bool();
+            bool mtrans = new bool();
+            bool munit = new bool();
+            int i_ = 0;
+
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                rc = 1;
+                return;
+            }
+            
+            //
+            // init
+            //
+            if( onenorm )
+            {
+                kase1 = 1;
+            }
+            else
+            {
+                kase1 = 2;
+            }
+            mupper = true;
+            mtrans = true;
+            munit = true;
+            work0 = new double[n+1];
+            work1 = new double[n+1];
+            work2 = new double[n+1];
+            work3 = new double[n+1];
+            iwork = new int[n+1];
+            
+            //
+            // Estimate the norm of A.
+            //
+            if( !isanormprovided )
+            {
+                kase = 0;
+                anorm = 0;
+                while( true )
+                {
+                    internalestimatenorm(n, ref work1, ref work0, ref iwork, ref anorm, ref kase);
+                    if( kase==0 )
+                    {
+                        break;
+                    }
+                    if( kase==kase1 )
+                    {
+                        
+                        //
+                        // Multiply by U
+                        //
+                        for(i=1; i<=n; i++)
+                        {
+                            v = 0.0;
+                            for(i_=i; i_<=n;i_++)
+                            {
+                                v += ludcmp[i,i_]*work0[i_];
+                            }
+                            work0[i] = v;
+                        }
+                        
+                        //
+                        // Multiply by L
+                        //
+                        for(i=n; i>=1; i--)
+                        {
+                            im1 = i-1;
+                            if( i>1 )
+                            {
+                                v = 0.0;
+                                for(i_=1; i_<=im1;i_++)
+                                {
+                                    v += ludcmp[i,i_]*work0[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            work0[i] = work0[i]+v;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Multiply by L'
+                        //
+                        for(i=1; i<=n; i++)
+                        {
+                            ip1 = i+1;
+                            v = 0.0;
+                            for(i_=ip1; i_<=n;i_++)
+                            {
+                                v += ludcmp[i_,i]*work0[i_];
+                            }
+                            work0[i] = work0[i]+v;
+                        }
+                        
+                        //
+                        // Multiply by U'
+                        //
+                        for(i=n; i>=1; i--)
+                        {
+                            v = 0.0;
+                            for(i_=1; i_<=i;i_++)
+                            {
+                                v += ludcmp[i_,i]*work0[i_];
+                            }
+                            work0[i] = v;
+                        }
+                    }
+                }
+            }
+            
+            //
+            // Quick return if possible
+            //
+            rc = 0;
+            if( (double)(anorm)==(double)(0) )
+            {
+                return;
+            }
+            
+            //
+            // Estimate the norm of inv(A).
+            //
+            smlnum = AP.Math.MinRealNumber;
+            ainvnm = 0;
+            normin = false;
+            kase = 0;
+            while( true )
+            {
+                internalestimatenorm(n, ref work1, ref work0, ref iwork, ref ainvnm, ref kase);
+                if( kase==0 )
+                {
+                    break;
+                }
+                if( kase==kase1 )
+                {
+                    
+                    //
+                    // Multiply by inv(L).
+                    //
+                    trlinsolve.safesolvetriangular(ref ludcmp, n, ref work0, ref sl, !mupper, !mtrans, munit, normin, ref work2);
+                    
+                    //
+                    // Multiply by inv(U).
+                    //
+                    trlinsolve.safesolvetriangular(ref ludcmp, n, ref work0, ref su, mupper, !mtrans, !munit, normin, ref work3);
+                }
+                else
+                {
+                    
+                    //
+                    // Multiply by inv(U').
+                    //
+                    trlinsolve.safesolvetriangular(ref ludcmp, n, ref work0, ref su, mupper, mtrans, !munit, normin, ref work3);
+                    
+                    //
+                    // Multiply by inv(L').
+                    //
+                    trlinsolve.safesolvetriangular(ref ludcmp, n, ref work0, ref sl, !mupper, mtrans, munit, normin, ref work2);
+                }
+                
+                //
+                // Divide X by 1/(SL*SU) if doing so will not cause overflow.
+                //
+                ascale = sl*su;
+                normin = true;
+                if( (double)(ascale)!=(double)(1) )
+                {
+                    ix = 1;
+                    for(i=2; i<=n; i++)
+                    {
+                        if( (double)(Math.Abs(work0[i]))>(double)(Math.Abs(work0[ix])) )
+                        {
+                            ix = i;
+                        }
+                    }
+                    if( (double)(ascale)<(double)(Math.Abs(work0[ix])*smlnum) | (double)(ascale)==(double)(0) )
+                    {
+                        return;
+                    }
+                    for(i=1; i<=n; i++)
+                    {
+                        work0[i] = work0[i]/ascale;
+                    }
+                }
+            }
+            
+            //
+            // Compute the estimate of the reciprocal condition number.
+            //
+            if( (double)(ainvnm)!=(double)(0) )
+            {
+                rc = 1/ainvnm;
+                rc = rc/anorm;
+            }
+        }
+
+
+        private static void internalestimatenorm(int n,
+            ref double[] v,
+            ref double[] x,
+            ref int[] isgn,
+            ref double est,
+            ref int kase)
+        {
+            int itmax = 0;
+            int i = 0;
+            double t = 0;
+            bool flg = new bool();
+            int positer = 0;
+            int posj = 0;
+            int posjlast = 0;
+            int posjump = 0;
+            int posaltsgn = 0;
+            int posestold = 0;
+            int postemp = 0;
+            int i_ = 0;
+
+            itmax = 5;
+            posaltsgn = n+1;
+            posestold = n+2;
+            postemp = n+3;
+            positer = n+1;
+            posj = n+2;
+            posjlast = n+3;
+            posjump = n+4;
+            if( kase==0 )
+            {
+                v = new double[n+3+1];
+                x = new double[n+1];
+                isgn = new int[n+4+1];
+                t = (double)(1)/(double)(n);
+                for(i=1; i<=n; i++)
+                {
+                    x[i] = t;
+                }
+                kase = 1;
+                isgn[posjump] = 1;
+                return;
+            }
+            
+            //
+            //     ................ ENTRY   (JUMP = 1)
+            //     FIRST ITERATION.  X HAS BEEN OVERWRITTEN BY A*X.
+            //
+            if( isgn[posjump]==1 )
+            {
+                if( n==1 )
+                {
+                    v[1] = x[1];
+                    est = Math.Abs(v[1]);
+                    kase = 0;
+                    return;
+                }
+                est = 0;
+                for(i=1; i<=n; i++)
+                {
+                    est = est+Math.Abs(x[i]);
+                }
+                for(i=1; i<=n; i++)
+                {
+                    if( (double)(x[i])>=(double)(0) )
+                    {
+                        x[i] = 1;
+                    }
+                    else
+                    {
+                        x[i] = -1;
+                    }
+                    isgn[i] = Math.Sign(x[i]);
+                }
+                kase = 2;
+                isgn[posjump] = 2;
+                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++)
+                {
+                    if( (double)(Math.Abs(x[i]))>(double)(Math.Abs(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;
+                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;
+                est = 0;
+                for(i=1; i<=n; i++)
+                {
+                    est = est+Math.Abs(v[i]);
+                }
+                flg = false;
+                for(i=1; i<=n; i++)
+                {
+                    if( (double)(x[i])>=(double)(0) & isgn[i]<0 | (double)(x[i])<(double)(0) & isgn[i]>=0 )
+                    {
+                        flg = true;
+                    }
+                }
+                
+                //
+                // REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED.
+                // OR MAY BE CYCLING.
+                //
+                if( !flg | (double)(est)<=(double)(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;
+                    return;
+                }
+                for(i=1; i<=n; i++)
+                {
+                    if( (double)(x[i])>=(double)(0) )
+                    {
+                        x[i] = 1;
+                        isgn[i] = 1;
+                    }
+                    else
+                    {
+                        x[i] = -1;
+                        isgn[i] = -1;
+                    }
+                }
+                kase = 2;
+                isgn[posjump] = 4;
+                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++)
+                {
+                    if( (double)(Math.Abs(x[i]))>(double)(Math.Abs(x[isgn[posj]])) )
+                    {
+                        isgn[posj] = i;
+                    }
+                }
+                if( (double)(x[isgn[posjlast]])!=(double)(Math.Abs(x[isgn[posj]])) & isgn[positer]<itmax )
+                {
+                    isgn[positer] = isgn[positer]+1;
+                    for(i=1; i<=n; i++)
+                    {
+                        x[i] = 0;
+                    }
+                    x[isgn[posj]] = 1;
+                    kase = 1;
+                    isgn[posjump] = 3;
+                    return;
+                }
+                
+                //
+                // ITERATION COMPLETE.  FINAL STAGE.
+                //
+                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;
+                return;
+            }
+            
+            //
+            //     ................ ENTRY   (JUMP = 5)
+            //     X HAS BEEN OVERWRITTEN BY A*X.
+            //
+            if( isgn[posjump]==5 )
+            {
+                v[postemp] = 0;
+                for(i=1; i<=n; i++)
+                {
+                    v[postemp] = v[postemp]+Math.Abs(x[i]);
+                }
+                v[postemp] = 2*v[postemp]/(3*n);
+                if( (double)(v[postemp])>(double)(est) )
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        v[i_] = x[i_];
+                    }
+                    est = v[postemp];
+                }
+                kase = 0;
+                return;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/reflections.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/reflections.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/reflections.cs	(revision 2645)
@@ -0,0 +1,330 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class reflections
+    {
+        /*************************************************************************
+        Generation of an elementary reflection transformation
+
+        The subroutine generates elementary reflection H of order N, so that, for
+        a given X, the following equality holds true:
+
+            ( X(1) )   ( Beta )
+        H * (  ..  ) = (  0   )
+            ( X(n) )   (  0   )
+
+        where
+                      ( V(1) )
+        H = 1 - Tau * (  ..  ) * ( V(1), ..., V(n) )
+                      ( V(n) )
+
+        where the first component of vector V equals 1.
+
+        Input parameters:
+            X   -   vector. Array whose index ranges within [1..N].
+            N   -   reflection order.
+
+        Output parameters:
+            X   -   components from 2 to N are replaced with vector V.
+                    The first component is replaced with parameter Beta.
+            Tau -   scalar value Tau. If X is a null vector, Tau equals 0,
+                    otherwise 1 <= Tau <= 2.
+
+        This subroutine is the modification of the DLARFG subroutines from
+        the LAPACK library.
+
+        MODIFICATIONS:
+            24.12.2005 sign(Alpha) was replaced with an analogous to the Fortran SIGN code.
+
+          -- LAPACK auxiliary routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             September 30, 1994
+        *************************************************************************/
+        public static void generatereflection(ref double[] x,
+            int n,
+            ref double tau)
+        {
+            int j = 0;
+            double alpha = 0;
+            double xnorm = 0;
+            double v = 0;
+            double beta = 0;
+            double mx = 0;
+            double s = 0;
+            int i_ = 0;
+
+            if( n<=1 )
+            {
+                tau = 0;
+                return;
+            }
+            
+            //
+            // Scale if needed (to avoid overflow/underflow during intermediate
+            // calculations).
+            //
+            mx = 0;
+            for(j=1; j<=n; j++)
+            {
+                mx = Math.Max(Math.Abs(x[j]), mx);
+            }
+            s = 1;
+            if( (double)(mx)!=(double)(0) )
+            {
+                if( (double)(mx)<=(double)(AP.Math.MinRealNumber/AP.Math.MachineEpsilon) )
+                {
+                    s = AP.Math.MinRealNumber/AP.Math.MachineEpsilon;
+                    v = 1/s;
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        x[i_] = v*x[i_];
+                    }
+                    mx = mx*v;
+                }
+                else
+                {
+                    if( (double)(mx)>=(double)(AP.Math.MaxRealNumber*AP.Math.MachineEpsilon) )
+                    {
+                        s = AP.Math.MaxRealNumber*AP.Math.MachineEpsilon;
+                        v = 1/s;
+                        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;
+            if( (double)(mx)!=(double)(0) )
+            {
+                for(j=2; j<=n; j++)
+                {
+                    xnorm = xnorm+AP.Math.Sqr(x[j]/mx);
+                }
+                xnorm = Math.Sqrt(xnorm)*mx;
+            }
+            if( (double)(xnorm)==(double)(0) )
+            {
+                
+                //
+                // H  =  I
+                //
+                tau = 0;
+                x[1] = x[1]*s;
+                return;
+            }
+            
+            //
+            // general case
+            //
+            mx = Math.Max(Math.Abs(alpha), Math.Abs(xnorm));
+            beta = -(mx*Math.Sqrt(AP.Math.Sqr(alpha/mx)+AP.Math.Sqr(xnorm/mx)));
+            if( (double)(alpha)<(double)(0) )
+            {
+                beta = -beta;
+            }
+            tau = (beta-alpha)/beta;
+            v = 1/(alpha-beta);
+            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
+        *************************************************************************/
+        public static void applyreflectionfromtheleft(ref double[,] c,
+            double tau,
+            ref double[] v,
+            int m1,
+            int m2,
+            int n1,
+            int n2,
+            ref double[] work)
+        {
+            double t = 0;
+            int i = 0;
+            int vm = 0;
+            int i_ = 0;
+
+            if( (double)(tau)==(double)(0) | n1>n2 | m1>m2 )
+            {
+                return;
+            }
+            
+            //
+            // 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];
+                for(i_=n1; i_<=n2;i_++)
+                {
+                    work[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,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
+        *************************************************************************/
+        public static void applyreflectionfromtheright(ref double[,] c,
+            double tau,
+            ref double[] v,
+            int m1,
+            int m2,
+            int n1,
+            int n2,
+            ref double[] work)
+        {
+            double t = 0;
+            int i = 0;
+            int vm = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( (double)(tau)==(double)(0) | n1>n2 | m1>m2 )
+            {
+                return;
+            }
+            
+            //
+            // w := C * v
+            //
+            vm = n2-n1+1;
+            for(i=m1; i<=m2; i++)
+            {
+                i1_ = (1)-(n1);
+                t = 0.0;
+                for(i_=n1; i_<=n2;i_++)
+                {
+                    t += c[i,i_]*v[i_+i1_];
+                }
+                work[i] = t;
+            }
+            
+            //
+            // C := C - w * v'
+            //
+            for(i=m1; i<=m2; i++)
+            {
+                t = work[i]*tau;
+                i1_ = (1) - (n1);
+                for(i_=n1; i_<=n2;i_++)
+                {
+                    c[i,i_] = c[i,i_] - t*v[i_+i1_];
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/rotations.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/rotations.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/rotations.cs	(revision 2645)
@@ -0,0 +1,411 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class rotations
+    {
+        /*************************************************************************
+        Application of a sequence of  elementary rotations to a matrix
+
+        The algorithm pre-multiplies the matrix by a sequence of rotation
+        transformations which is given by arrays C and S. Depending on the value
+        of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true)
+        rows are rotated, or the rows N and N-1, N-2 and N-3 and so on, are rotated.
+
+        Not the whole matrix but only a part of it is transformed (rows from M1 to
+        M2, columns from N1 to N2). Only the elements of this submatrix are changed.
+
+        Input parameters:
+            IsForward   -   the sequence of the rotation application.
+            M1,M2       -   the range of rows to be transformed.
+            N1, N2      -   the range of columns to be transformed.
+            C,S         -   transformation coefficients.
+                            Array whose index ranges within [1..M2-M1].
+            A           -   processed matrix.
+            WORK        -   working array whose index ranges within [N1..N2].
+
+        Output parameters:
+            A           -   transformed matrix.
+
+        Utility subroutine.
+        *************************************************************************/
+        public static void applyrotationsfromtheleft(bool isforward,
+            int m1,
+            int m2,
+            int n1,
+            int n2,
+            ref double[] c,
+            ref double[] s,
+            ref double[,] a,
+            ref double[] work)
+        {
+            int j = 0;
+            int jp1 = 0;
+            double ctemp = 0;
+            double stemp = 0;
+            double temp = 0;
+            int i_ = 0;
+
+            if( m1>m2 | n1>n2 )
+            {
+                return;
+            }
+            
+            //
+            // Form  P * A
+            //
+            if( isforward )
+            {
+                if( n1!=n2 )
+                {
+                    
+                    //
+                    // Common case: N1<>N2
+                    //
+                    for(j=m1; j<=m2-1; j++)
+                    {
+                        ctemp = c[j-m1+1];
+                        stemp = s[j-m1+1];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            jp1 = j+1;
+                            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,i_] = ctemp*a[j,i_];
+                            }
+                            for(i_=n1; i_<=n2;i_++)
+                            {
+                                a[j,i_] = a[j,i_] + stemp*a[jp1,i_];
+                            }
+                            for(i_=n1; i_<=n2;i_++)
+                            {
+                                a[jp1,i_] = work[i_];
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // Special case: N1=N2
+                    //
+                    for(j=m1; j<=m2-1; j++)
+                    {
+                        ctemp = c[j-m1+1];
+                        stemp = s[j-m1+1];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            temp = a[j+1,n1];
+                            a[j+1,n1] = ctemp*temp-stemp*a[j,n1];
+                            a[j,n1] = stemp*temp+ctemp*a[j,n1];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if( n1!=n2 )
+                {
+                    
+                    //
+                    // Common case: N1<>N2
+                    //
+                    for(j=m2-1; j>=m1; j--)
+                    {
+                        ctemp = c[j-m1+1];
+                        stemp = s[j-m1+1];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            jp1 = j+1;
+                            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,i_] = ctemp*a[j,i_];
+                            }
+                            for(i_=n1; i_<=n2;i_++)
+                            {
+                                a[j,i_] = a[j,i_] + stemp*a[jp1,i_];
+                            }
+                            for(i_=n1; i_<=n2;i_++)
+                            {
+                                a[jp1,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];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            temp = a[j+1,n1];
+                            a[j+1,n1] = ctemp*temp-stemp*a[j,n1];
+                            a[j,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.
+        *************************************************************************/
+        public static void applyrotationsfromtheright(bool isforward,
+            int m1,
+            int m2,
+            int n1,
+            int n2,
+            ref double[] c,
+            ref double[] s,
+            ref double[,] a,
+            ref double[] work)
+        {
+            int j = 0;
+            int jp1 = 0;
+            double ctemp = 0;
+            double stemp = 0;
+            double temp = 0;
+            int i_ = 0;
+
+            
+            //
+            // Form A * P'
+            //
+            if( isforward )
+            {
+                if( m1!=m2 )
+                {
+                    
+                    //
+                    // Common case: M1<>M2
+                    //
+                    for(j=n1; j<=n2-1; j++)
+                    {
+                        ctemp = c[j-n1+1];
+                        stemp = s[j-n1+1];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            jp1 = j+1;
+                            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];
+                            }
+                            for(i_=m1; i_<=m2;i_++)
+                            {
+                                a[i_,j] = ctemp*a[i_,j];
+                            }
+                            for(i_=m1; i_<=m2;i_++)
+                            {
+                                a[i_,j] = a[i_,j] + stemp*a[i_,jp1];
+                            }
+                            for(i_=m1; i_<=m2;i_++)
+                            {
+                                a[i_,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];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            temp = a[m1,j+1];
+                            a[m1,j+1] = ctemp*temp-stemp*a[m1,j];
+                            a[m1,j] = stemp*temp+ctemp*a[m1,j];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if( m1!=m2 )
+                {
+                    
+                    //
+                    // Common case: M1<>M2
+                    //
+                    for(j=n2-1; j>=n1; j--)
+                    {
+                        ctemp = c[j-n1+1];
+                        stemp = s[j-n1+1];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            jp1 = j+1;
+                            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];
+                            }
+                            for(i_=m1; i_<=m2;i_++)
+                            {
+                                a[i_,j] = ctemp*a[i_,j];
+                            }
+                            for(i_=m1; i_<=m2;i_++)
+                            {
+                                a[i_,j] = a[i_,j] + stemp*a[i_,jp1];
+                            }
+                            for(i_=m1; i_<=m2;i_++)
+                            {
+                                a[i_,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];
+                        if( (double)(ctemp)!=(double)(1) | (double)(stemp)!=(double)(0) )
+                        {
+                            temp = a[m1,j+1];
+                            a[m1,j+1] = ctemp*temp-stemp*a[m1,j];
+                            a[m1,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
+        *************************************************************************/
+        public static void generaterotation(double f,
+            double g,
+            ref double cs,
+            ref double sn,
+            ref double r)
+        {
+            double f1 = 0;
+            double g1 = 0;
+
+            if( (double)(g)==(double)(0) )
+            {
+                cs = 1;
+                sn = 0;
+                r = f;
+            }
+            else
+            {
+                if( (double)(f)==(double)(0) )
+                {
+                    cs = 0;
+                    sn = 1;
+                    r = g;
+                }
+                else
+                {
+                    f1 = f;
+                    g1 = g;
+                    r = Math.Sqrt(AP.Math.Sqr(f1)+AP.Math.Sqr(g1));
+                    cs = f1/r;
+                    sn = g1/r;
+                    if( (double)(Math.Abs(f))>(double)(Math.Abs(g)) & (double)(cs)<(double)(0) )
+                    {
+                        cs = -cs;
+                        sn = -sn;
+                        r = -r;
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sbisinv.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sbisinv.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sbisinv.cs	(revision 2645)
@@ -0,0 +1,209 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class sbisinv
+    {
+        /*************************************************************************
+        Subroutine for finding the eigenvalues (and eigenvectors) of  a  symmetric
+        matrix  in  a  given half open interval (A, B] by using  a  bisection  and
+        inverse iteration
+
+        Input parameters:
+            A       -   symmetric matrix which is given by its upper or lower
+                        triangular part. Array [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            ZNeeded -   flag controlling whether the eigenvectors are needed or not.
+                        If ZNeeded is equal to:
+                         * 0, the eigenvectors are not returned;
+                         * 1, the eigenvectors are returned.
+            IsUpperA -  storage format of matrix A.
+            B1, B2 -    half open interval (B1, B2] to search eigenvalues in.
+
+        Output parameters:
+            M       -   number of eigenvalues found in a given half-interval (M>=0).
+            W       -   array of the eigenvalues found.
+                        Array whose index ranges within [0..M-1].
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z hasnt changed;
+                         * 1, Z contains eigenvectors.
+                        Array whose indexes range within [0..N-1, 0..M-1].
+                        The eigenvectors are stored in the matrix columns.
+
+        Result:
+            True, if successful. M contains the number of eigenvalues in the given
+            half-interval (could be equal to 0), W contains the eigenvalues,
+            Z contains the eigenvectors (if needed).
+
+            False, if the bisection method subroutine wasn't able to find the
+            eigenvalues in the given interval or if the inverse iteration subroutine
+            wasn't able to find all the corresponding eigenvectors.
+            In that case, the eigenvalues and eigenvectors are not returned,
+            M is equal to 0.
+
+          -- ALGLIB --
+             Copyright 07.01.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixevdr(double[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            double b1,
+            double b2,
+            ref int m,
+            ref double[] w,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] e = new double[0];
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "SMatrixTDEVDR: incorrect ZNeeded");
+            tridiagonal.smatrixtd(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                tridiagonal.smatrixtdunpackq(ref a, n, isupper, ref tau, ref z);
+            }
+            result = tdbisinv.smatrixtdevdr(ref w, ref e, n, zneeded, b1, b2, ref m, ref z);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Subroutine for finding the eigenvalues and  eigenvectors  of  a  symmetric
+        matrix with given indexes by using bisection and inverse iteration methods.
+
+        Input parameters:
+            A       -   symmetric matrix which is given by its upper or lower
+                        triangular part. Array whose indexes range within [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            ZNeeded -   flag controlling whether the eigenvectors are needed or not.
+                        If ZNeeded is equal to:
+                         * 0, the eigenvectors are not returned;
+                         * 1, the eigenvectors are returned.
+            IsUpperA -  storage format of matrix A.
+            I1, I2 -    index interval for searching (from I1 to I2).
+                        0 <= I1 <= I2 <= N-1.
+
+        Output parameters:
+            W       -   array of the eigenvalues found.
+                        Array whose index ranges within [0..I2-I1].
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z hasnt changed;
+                         * 1, Z contains eigenvectors.
+                        Array whose indexes range within [0..N-1, 0..I2-I1].
+                        In that case, the eigenvectors are stored in the matrix columns.
+
+        Result:
+            True, if successful. W contains the eigenvalues, Z contains the
+            eigenvectors (if needed).
+
+            False, if the bisection method subroutine wasn't able to find the
+            eigenvalues in the given interval or if the inverse iteration subroutine
+            wasn't able to find all the corresponding eigenvectors.
+            In that case, the eigenvalues and eigenvectors are not returned.
+
+          -- ALGLIB --
+             Copyright 07.01.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixevdi(double[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            int i1,
+            int i2,
+            ref double[] w,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] e = new double[0];
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "SMatrixEVDI: incorrect ZNeeded");
+            tridiagonal.smatrixtd(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                tridiagonal.smatrixtdunpackq(ref a, n, isupper, ref tau, ref z);
+            }
+            result = tdbisinv.smatrixtdevdi(ref w, ref e, n, zneeded, i1, i2, ref z);
+            return result;
+        }
+
+
+        public static bool symmetriceigenvaluesandvectorsininterval(double[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            double b1,
+            double b2,
+            ref int m,
+            ref double[] w,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] e = new double[0];
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "SymmetricEigenValuesAndVectorsInInterval: incorrect ZNeeded");
+            tridiagonal.totridiagonal(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                tridiagonal.unpackqfromtridiagonal(ref a, n, isupper, ref tau, ref z);
+            }
+            result = tdbisinv.tridiagonaleigenvaluesandvectorsininterval(ref w, ref e, n, zneeded, b1, b2, ref m, ref z);
+            return result;
+        }
+
+
+        public static bool symmetriceigenvaluesandvectorsbyindexes(double[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            int i1,
+            int i2,
+            ref double[] w,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] e = new double[0];
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "SymmetricEigenValuesAndVectorsInInterval: incorrect ZNeeded");
+            tridiagonal.totridiagonal(ref a, n, isupper, ref tau, ref w, ref e);
+            if( zneeded==1 )
+            {
+                tridiagonal.unpackqfromtridiagonal(ref a, n, isupper, ref tau, ref z);
+            }
+            result = tdbisinv.tridiagonaleigenvaluesandvectorsbyindexes(ref w, ref e, n, zneeded, i1, i2, ref z);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sblas.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sblas.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sblas.cs	(revision 2645)
@@ -0,0 +1,226 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class sblas
+    {
+        public static void symmetricmatrixvectormultiply(ref double[,] a,
+            bool isupper,
+            int i1,
+            int i2,
+            ref double[] x,
+            double alpha,
+            ref double[] y)
+        {
+            int i = 0;
+            int ba1 = 0;
+            int ba2 = 0;
+            int by1 = 0;
+            int by2 = 0;
+            int bx1 = 0;
+            int bx2 = 0;
+            int n = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            n = i2-i1+1;
+            if( n<=0 )
+            {
+                return;
+            }
+            
+            //
+            // Let A = L + D + U, where
+            //  L is strictly lower triangular (main diagonal is zero)
+            //  D is diagonal
+            //  U is strictly upper triangular (main diagonal is zero)
+            //
+            // A*x = L*x + D*x + U*x
+            //
+            // Calculate D*x first
+            //
+            for(i=i1; i<=i2; i++)
+            {
+                y[i-i1+1] = a[i,i]*x[i-i1+1];
+            }
+            
+            //
+            // Add L*x + U*x
+            //
+            if( isupper )
+            {
+                for(i=i1; i<=i2-1; i++)
+                {
+                    
+                    //
+                    // Add L*x to the result
+                    //
+                    v = x[i-i1+1];
+                    by1 = i-i1+2;
+                    by2 = n;
+                    ba1 = i+1;
+                    ba2 = i2;
+                    i1_ = (ba1) - (by1);
+                    for(i_=by1; i_<=by2;i_++)
+                    {
+                        y[i_] = y[i_] + v*a[i,i_+i1_];
+                    }
+                    
+                    //
+                    // Add U*x to the result
+                    //
+                    bx1 = i-i1+2;
+                    bx2 = n;
+                    ba1 = i+1;
+                    ba2 = i2;
+                    i1_ = (ba1)-(bx1);
+                    v = 0.0;
+                    for(i_=bx1; i_<=bx2;i_++)
+                    {
+                        v += x[i_]*a[i,i_+i1_];
+                    }
+                    y[i-i1+1] = y[i-i1+1]+v;
+                }
+            }
+            else
+            {
+                for(i=i1+1; i<=i2; i++)
+                {
+                    
+                    //
+                    // Add L*x to the result
+                    //
+                    bx1 = 1;
+                    bx2 = i-i1;
+                    ba1 = i1;
+                    ba2 = i-1;
+                    i1_ = (ba1)-(bx1);
+                    v = 0.0;
+                    for(i_=bx1; i_<=bx2;i_++)
+                    {
+                        v += x[i_]*a[i,i_+i1_];
+                    }
+                    y[i-i1+1] = y[i-i1+1]+v;
+                    
+                    //
+                    // Add U*x to the result
+                    //
+                    v = x[i-i1+1];
+                    by1 = 1;
+                    by2 = i-i1;
+                    ba1 = i1;
+                    ba2 = i-1;
+                    i1_ = (ba1) - (by1);
+                    for(i_=by1; i_<=by2;i_++)
+                    {
+                        y[i_] = y[i_] + v*a[i,i_+i1_];
+                    }
+                }
+            }
+            for(i_=1; i_<=n;i_++)
+            {
+                y[i_] = alpha*y[i_];
+            }
+        }
+
+
+        public static void symmetricrank2update(ref double[,] a,
+            bool isupper,
+            int i1,
+            int i2,
+            ref double[] x,
+            ref double[] y,
+            ref double[] t,
+            double alpha)
+        {
+            int i = 0;
+            int tp1 = 0;
+            int tp2 = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( isupper )
+            {
+                for(i=i1; i<=i2; i++)
+                {
+                    tp1 = i+1-i1;
+                    tp2 = i2-i1+1;
+                    v = x[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = v*y[i_];
+                    }
+                    v = y[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = t[i_] + v*x[i_];
+                    }
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = alpha*t[i_];
+                    }
+                    i1_ = (tp1) - (i);
+                    for(i_=i; i_<=i2;i_++)
+                    {
+                        a[i,i_] = a[i,i_] + t[i_+i1_];
+                    }
+                }
+            }
+            else
+            {
+                for(i=i1; i<=i2; i++)
+                {
+                    tp1 = 1;
+                    tp2 = i+1-i1;
+                    v = x[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = v*y[i_];
+                    }
+                    v = y[i+1-i1];
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = t[i_] + v*x[i_];
+                    }
+                    for(i_=tp1; i_<=tp2;i_++)
+                    {
+                        t[i_] = alpha*t[i_];
+                    }
+                    i1_ = (tp1) - (i1);
+                    for(i_=i1; i_<=i;i_++)
+                    {
+                        a[i,i_] = a[i,i_] + t[i_+i1_];
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/schur.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/schur.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/schur.cs	(revision 2645)
@@ -0,0 +1,146 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class schur
+    {
+        /*************************************************************************
+        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).
+        *************************************************************************/
+        public static bool rmatrixschur(ref double[,] a,
+            int n,
+            ref double[,] s)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] wi = new double[0];
+            double[] wr = new double[0];
+            double[,] a1 = new double[0,0];
+            double[,] s1 = new double[0,0];
+            int info = 0;
+            int i = 0;
+            int j = 0;
+
+            
+            //
+            // Upper Hessenberg form of the 0-based matrix
+            //
+            hessenberg.rmatrixhessenberg(ref a, n, ref tau);
+            hessenberg.rmatrixhessenbergunpackq(ref a, n, ref tau, ref 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 = new double[n+1, n+1];
+            s1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    a1[i,j] = a[i-1,j-1];
+                    s1[i,j] = s[i-1,j-1];
+                }
+            }
+            hsschur.internalschurdecomposition(ref a1, n, 1, 1, ref wr, ref wi, ref s1, ref 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,j-1] = a1[i,j];
+                    s[i-1,j-1] = s1[i,j];
+                }
+            }
+            return result;
+        }
+
+
+        public static bool schurdecomposition(ref double[,] a,
+            int n,
+            ref double[,] s)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] wi = new double[0];
+            double[] wr = new double[0];
+            int info = 0;
+
+            hessenberg.toupperhessenberg(ref a, n, ref tau);
+            hessenberg.unpackqfromupperhessenberg(ref a, n, ref tau, ref s);
+            hsschur.internalschurdecomposition(ref a, n, 1, 1, ref wr, ref wi, ref s, ref info);
+            result = info==0;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sdet.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sdet.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sdet.cs	(revision 2645)
@@ -0,0 +1,185 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class sdet
+    {
+        /*************************************************************************
+        Determinant calculation of the matrix given by LDLT decomposition.
+
+        Input parameters:
+            A       -   LDLT-decomposition of the matrix,
+                        output of subroutine SMatrixLDLT.
+            Pivots  -   table of permutations which were made during
+                        LDLT decomposition, output of subroutine SMatrixLDLT.
+            N       -   size of matrix A.
+            IsUpper -   matrix storage format. The value is equal to the input
+                        parameter of subroutine SMatrixLDLT.
+
+        Result:
+            matrix determinant.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double smatrixldltdet(ref double[,] a,
+            ref int[] pivots,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int k = 0;
+
+            result = 1;
+            if( isupper )
+            {
+                k = 0;
+                while( k<n )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        result = result*a[k,k];
+                        k = k+1;
+                    }
+                    else
+                    {
+                        result = result*(a[k,k]*a[k+1,k+1]-a[k,k+1]*a[k,k+1]);
+                        k = k+2;
+                    }
+                }
+            }
+            else
+            {
+                k = n-1;
+                while( k>=0 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        result = result*a[k,k];
+                        k = k-1;
+                    }
+                    else
+                    {
+                        result = result*(a[k-1,k-1]*a[k,k]-a[k,k-1]*a[k,k-1]);
+                        k = k-2;
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Determinant calculation of the symmetric matrix
+
+        Input parameters:
+            A       -   matrix. Array with elements [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   if IsUpper = True, then symmetric matrix A is given by its
+                        upper triangle, and the lower triangle isnt used by
+                        subroutine. Similarly, if IsUpper = False, then A is given
+                        by its lower triangle.
+
+        Result:
+            determinant of matrix A.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double smatrixdet(double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            ldlt.smatrixldlt(ref a, n, isupper, ref pivots);
+            result = smatrixldltdet(ref a, ref pivots, n, isupper);
+            return result;
+        }
+
+
+        public static double determinantldlt(ref double[,] a,
+            ref int[] pivots,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int k = 0;
+
+            result = 1;
+            if( isupper )
+            {
+                k = 1;
+                while( k<=n )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        result = result*a[k,k];
+                        k = k+1;
+                    }
+                    else
+                    {
+                        result = result*(a[k,k]*a[k+1,k+1]-a[k,k+1]*a[k,k+1]);
+                        k = k+2;
+                    }
+                }
+            }
+            else
+            {
+                k = n;
+                while( k>=1 )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        result = result*a[k,k];
+                        k = k-1;
+                    }
+                    else
+                    {
+                        result = result*(a[k-1,k-1]*a[k,k]-a[k,k-1]*a[k,k-1]);
+                        k = k-2;
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static double determinantsymmetric(double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            ldlt.ldltdecomposition(ref a, n, isupper, ref pivots);
+            result = determinantldlt(ref a, ref pivots, n, isupper);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sevd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sevd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sevd.cs	(revision 2645)
@@ -0,0 +1,107 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class sevd
+    {
+        /*************************************************************************
+        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.
+            IsUpper -   storage format.
+            ZNeeded -   flag controlling whether the eigenvectors are needed or not.
+                        If ZNeeded is equal to:
+                         * 0, the eigenvectors are not returned;
+                         * 1, the eigenvectors are returned.
+
+        Output parameters:
+            D       -   eigenvalues in ascending order.
+                        Array whose index ranges within [0..N-1].
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z hasnt changed;
+                         * 1, Z contains the eigenvectors.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+                        The eigenvectors are stored in the matrix columns.
+
+        Result:
+            True, if the algorithm has converged.
+            False, if the algorithm hasn't converged (rare case).
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixevd(double[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            ref double[] d,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] e = new double[0];
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "SMatrixEVD: incorrect ZNeeded");
+            tridiagonal.smatrixtd(ref a, n, isupper, ref tau, ref d, ref e);
+            if( zneeded==1 )
+            {
+                tridiagonal.smatrixtdunpackq(ref a, n, isupper, ref tau, ref z);
+            }
+            result = tdevd.smatrixtdevd(ref d, e, n, zneeded, ref z);
+            return result;
+        }
+
+
+        public static bool symmetricevd(double[,] a,
+            int n,
+            int zneeded,
+            bool isupper,
+            ref double[] d,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] tau = new double[0];
+            double[] e = new double[0];
+
+            a = (double[,])a.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded==0 | zneeded==1, "SymmetricEVD: incorrect ZNeeded");
+            tridiagonal.totridiagonal(ref a, n, isupper, ref tau, ref d, ref e);
+            if( zneeded==1 )
+            {
+                tridiagonal.unpackqfromtridiagonal(ref a, n, isupper, ref tau, ref z);
+            }
+            result = tdevd.tridiagonalevd(ref d, e, n, zneeded, ref z);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sinverse.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sinverse.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/sinverse.cs	(revision 2645)
@@ -0,0 +1,904 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class sinverse
+    {
+        /*************************************************************************
+        Inversion of a symmetric indefinite matrix
+
+        The algorithm gets an LDLT-decomposition as an input, generates matrix A^-1
+        and saves the lower or upper triangle of an inverse matrix depending on the
+        input (U*D*U' or L*D*L').
+
+        Input parameters:
+            A       -   LDLT-decomposition of the matrix,
+                        Output of subroutine SMatrixLDLT.
+            N       -   size of matrix A.
+            IsUpper -   storage format. If IsUpper = True, then the symmetric matrix
+                        is given as decomposition A = U*D*U' and this decomposition
+                        is stored in the upper triangle of matrix A and on the main
+                        diagonal, and the lower triangle of matrix A is not used.
+            Pivots  -   a table of permutations, output of subroutine SMatrixLDLT.
+
+        Output parameters:
+            A       -   inverse of the matrix, whose LDLT-decomposition was stored
+                        in matrix A as a subroutine input.
+                        Array with elements [0..N-1, 0..N-1].
+                        If IsUpper = True, then A contains the upper triangle of
+                        matrix A^-1, and the elements below the main diagonal are
+                        not used nor changed. The same applies if IsUpper = False.
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular and could not be inverted.
+
+          -- LAPACK routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             March 31, 1993
+        *************************************************************************/
+        public static bool smatrixldltinverse(ref double[,] a,
+            ref int[] pivots,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            double[] work = new double[0];
+            double[] work2 = new double[0];
+            int i = 0;
+            int k = 0;
+            int kp = 0;
+            int kstep = 0;
+            double ak = 0;
+            double akkp1 = 0;
+            double akp1 = 0;
+            double d = 0;
+            double t = 0;
+            double temp = 0;
+            int km1 = 0;
+            int kp1 = 0;
+            int l = 0;
+            int i1 = 0;
+            int i2 = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            work = new double[n+1];
+            work2 = new double[n+1];
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            
+            //
+            // Check that the diagonal matrix D is nonsingular.
+            //
+            for(i=0; i<=n-1; i++)
+            {
+                if( pivots[i]>=0 & (double)(a[i,i])==(double)(0) )
+                {
+                    result = false;
+                    return result;
+                }
+            }
+            if( isupper )
+            {
+                
+                //
+                // Compute inv(A) from the factorization A = U*D*U'.
+                //
+                // K+1 is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = 0;
+                while( k<=n-1 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        a[k,k] = 1/a[k,k];
+                        
+                        //
+                        // Compute column K+1 of the inverse.
+                        //
+                        if( k>0 )
+                        {
+                            i1_ = (0) - (1);
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, 1-1, k+1-1-1, ref work, -1, ref work2);
+                            i1_ = (1) - (0);
+                            for(i_=0; i_<=k-1;i_++)
+                            {
+                                a[i_,k] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                v += work2[i_]*work[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                        }
+                        kstep = 1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        t = Math.Abs(a[k,k+1]);
+                        ak = a[k,k]/t;
+                        akp1 = a[k+1,k+1]/t;
+                        akkp1 = a[k,k+1]/t;
+                        d = t*(ak*akp1-1);
+                        a[k,k] = akp1/d;
+                        a[k+1,k+1] = ak/d;
+                        a[k,k+1] = -(akkp1/d);
+                        
+                        //
+                        // Compute columns K+1 and K+1+1 of the inverse.
+                        //
+                        if( k>0 )
+                        {
+                            i1_ = (0) - (1);
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, 0, k-1, ref work, -1, ref work2);
+                            i1_ = (1) - (0);
+                            for(i_=0; i_<=k-1;i_++)
+                            {
+                                a[i_,k] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                            v = 0.0;
+                            for(i_=0; i_<=k-1;i_++)
+                            {
+                                v += a[i_,k]*a[i_,k+1];
+                            }
+                            a[k,k+1] = a[k,k+1]-v;
+                            i1_ = (0) - (1);
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k+1];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, 0, k-1, ref work, -1, ref work2);
+                            i1_ = (1) - (0);
+                            for(i_=0; i_<=k-1;i_++)
+                            {
+                                a[i_,k+1] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=k;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k+1,k+1] = a[k+1,k+1]-v;
+                        }
+                        kstep = 2;
+                    }
+                    if( pivots[k]>=0 )
+                    {
+                        kp = pivots[k];
+                    }
+                    else
+                    {
+                        kp = n+pivots[k];
+                    }
+                    if( kp!=k )
+                    {
+                        
+                        //
+                        // Interchange rows and columns K and KP in the leading
+                        // submatrix
+                        //
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=kp;i_++)
+                        {
+                            work[i_] = a[i_+i1_,k];
+                        }
+                        for(i_=0; i_<=kp-1;i_++)
+                        {
+                            a[i_,k] = a[i_,kp];
+                        }
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=kp-1;i_++)
+                        {
+                            a[i_,kp] = work[i_+i1_];
+                        }
+                        i1_ = (kp+1) - (1);
+                        for(i_=1; i_<=k-1-kp;i_++)
+                        {
+                            work[i_] = a[i_+i1_,k];
+                        }
+                        for(i_=kp+1; i_<=k-1;i_++)
+                        {
+                            a[i_,k] = a[kp,i_];
+                        }
+                        i1_ = (1) - (kp+1);
+                        for(i_=kp+1; i_<=k-1;i_++)
+                        {
+                            a[kp,i_] = work[i_+i1_];
+                        }
+                        temp = a[k,k];
+                        a[k,k] = a[kp,kp];
+                        a[kp,kp] = temp;
+                        if( kstep==2 )
+                        {
+                            temp = a[k,k+1];
+                            a[k,k+1] = a[kp,k+1];
+                            a[kp,k+1] = temp;
+                        }
+                    }
+                    k = k+kstep;
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inv(A) from the factorization A = L*D*L'.
+                //
+                // K is the main loop index, increasing from 0 to N-1 in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = n-1;
+                while( k>=0 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        a[k,k] = 1/a[k,k];
+                        
+                        //
+                        // Compute column K+1 of the inverse.
+                        //
+                        if( k<n-1 )
+                        {
+                            i1_ = (k+1) - (1);
+                            for(i_=1; i_<=n-k-1;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, k+1, n-1, ref work, -1, ref work2);
+                            i1_ = (1) - (k+1);
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                a[i_,k] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=n-k-1;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                        }
+                        kstep = 1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        t = Math.Abs(a[k,k-1]);
+                        ak = a[k-1,k-1]/t;
+                        akp1 = a[k,k]/t;
+                        akkp1 = a[k,k-1]/t;
+                        d = t*(ak*akp1-1);
+                        a[k-1,k-1] = akp1/d;
+                        a[k,k] = ak/d;
+                        a[k,k-1] = -(akkp1/d);
+                        
+                        //
+                        // Compute columns K+1-1 and K+1 of the inverse.
+                        //
+                        if( k<n-1 )
+                        {
+                            i1_ = (k+1) - (1);
+                            for(i_=1; i_<=n-k-1;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, k+1, n-1, ref work, -1, ref work2);
+                            i1_ = (1) - (k+1);
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                a[i_,k] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=n-k-1;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                            v = 0.0;
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                v += a[i_,k]*a[i_,k-1];
+                            }
+                            a[k,k-1] = a[k,k-1]-v;
+                            i1_ = (k+1) - (1);
+                            for(i_=1; i_<=n-k-1;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k-1];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, k+1, n-1, ref work, -1, ref work2);
+                            i1_ = (1) - (k+1);
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                a[i_,k-1] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=n-k-1;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k-1,k-1] = a[k-1,k-1]-v;
+                        }
+                        kstep = 2;
+                    }
+                    if( pivots[k]>=0 )
+                    {
+                        kp = pivots[k];
+                    }
+                    else
+                    {
+                        kp = pivots[k]+n;
+                    }
+                    if( kp!=k )
+                    {
+                        
+                        //
+                        // Interchange rows and columns K and KP
+                        //
+                        if( kp<n-1 )
+                        {
+                            i1_ = (kp+1) - (1);
+                            for(i_=1; i_<=n-kp-1;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            for(i_=kp+1; i_<=n-1;i_++)
+                            {
+                                a[i_,k] = a[i_,kp];
+                            }
+                            i1_ = (1) - (kp+1);
+                            for(i_=kp+1; i_<=n-1;i_++)
+                            {
+                                a[i_,kp] = work[i_+i1_];
+                            }
+                        }
+                        i1_ = (k+1) - (1);
+                        for(i_=1; i_<=kp-k-1;i_++)
+                        {
+                            work[i_] = a[i_+i1_,k];
+                        }
+                        for(i_=k+1; i_<=kp-1;i_++)
+                        {
+                            a[i_,k] = a[kp,i_];
+                        }
+                        i1_ = (1) - (k+1);
+                        for(i_=k+1; i_<=kp-1;i_++)
+                        {
+                            a[kp,i_] = work[i_+i1_];
+                        }
+                        temp = a[k,k];
+                        a[k,k] = a[kp,kp];
+                        a[kp,kp] = temp;
+                        if( kstep==2 )
+                        {
+                            temp = a[k,k-1];
+                            a[k,k-1] = a[kp,k-1];
+                            a[kp,k-1] = temp;
+                        }
+                    }
+                    k = k-kstep;
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Inversion of a symmetric indefinite matrix
+
+        Given a lower or upper triangle of matrix A, the algorithm generates
+        matrix A^-1 and saves the lower or upper 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.
+            IsUpper -   storage format. If IsUpper = True, then the upper
+                        triangle of matrix A is given, otherwise the lower
+                        triangle is given.
+
+        Output parameters:
+            A       -   inverse of matrix A.
+                        Array with elements [0..N-1, 0..N-1].
+                        If IsUpper = True, then A contains the upper triangle of
+                        matrix A^-1, and the elements below the main diagonal are
+                        not used nor changed.
+                        The same applies if IsUpper = False.
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular and could not be inverted.
+
+          -- LAPACK routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             March 31, 1993
+        *************************************************************************/
+        public static bool smatrixinverse(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            ldlt.smatrixldlt(ref a, n, isupper, ref pivots);
+            result = smatrixldltinverse(ref a, ref pivots, n, isupper);
+            return result;
+        }
+
+
+        public static bool inverseldlt(ref double[,] a,
+            ref int[] pivots,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            double[] work = new double[0];
+            double[] work2 = new double[0];
+            int i = 0;
+            int k = 0;
+            int kp = 0;
+            int kstep = 0;
+            double ak = 0;
+            double akkp1 = 0;
+            double akp1 = 0;
+            double d = 0;
+            double t = 0;
+            double temp = 0;
+            int km1 = 0;
+            int kp1 = 0;
+            int l = 0;
+            int i1 = 0;
+            int i2 = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            work = new double[n+1];
+            work2 = new double[n+1];
+            result = true;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return result;
+            }
+            
+            //
+            // Check that the diagonal matrix D is nonsingular.
+            //
+            for(i=1; i<=n; i++)
+            {
+                if( pivots[i]>0 & (double)(a[i,i])==(double)(0) )
+                {
+                    result = false;
+                    return result;
+                }
+            }
+            if( isupper )
+            {
+                
+                //
+                // Compute inv(A) from the factorization A = U*D*U'.
+                //
+                // K is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = 1;
+                while( k<=n )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        a[k,k] = 1/a[k,k];
+                        
+                        //
+                        // Compute column K of the inverse.
+                        //
+                        if( k>1 )
+                        {
+                            km1 = k-1;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                work[i_] = a[i_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, 1, k-1, ref work, -1, ref work2);
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                a[i_,k] = work2[i_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                v += work2[i_]*work[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                        }
+                        kstep = 1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        t = Math.Abs(a[k,k+1]);
+                        ak = a[k,k]/t;
+                        akp1 = a[k+1,k+1]/t;
+                        akkp1 = a[k,k+1]/t;
+                        d = t*(ak*akp1-1);
+                        a[k,k] = akp1/d;
+                        a[k+1,k+1] = ak/d;
+                        a[k,k+1] = -(akkp1/d);
+                        
+                        //
+                        // Compute columns K and K+1 of the inverse.
+                        //
+                        if( k>1 )
+                        {
+                            km1 = k-1;
+                            kp1 = k+1;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                work[i_] = a[i_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, 1, k-1, ref work, -1, ref work2);
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                a[i_,k] = work2[i_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                            v = 0.0;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                v += a[i_,k]*a[i_,kp1];
+                            }
+                            a[k,k+1] = a[k,k+1]-v;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                work[i_] = a[i_,kp1];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, 1, k-1, ref work, -1, ref work2);
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                a[i_,kp1] = work2[i_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=km1;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k+1,k+1] = a[k+1,k+1]-v;
+                        }
+                        kstep = 2;
+                    }
+                    kp = Math.Abs(pivots[k]);
+                    if( kp!=k )
+                    {
+                        
+                        //
+                        // Interchange rows and columns K and KP in the leading
+                        // submatrix A(1:k+1,1:k+1)
+                        //
+                        l = kp-1;
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            work[i_] = a[i_,k];
+                        }
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            a[i_,k] = a[i_,kp];
+                        }
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            a[i_,kp] = work[i_];
+                        }
+                        l = k-kp-1;
+                        i1 = kp+1;
+                        i2 = k-1;
+                        i1_ = (i1) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            work[i_] = a[i_+i1_,k];
+                        }
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            a[i_,k] = a[kp,i_];
+                        }
+                        i1_ = (1) - (i1);
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            a[kp,i_] = work[i_+i1_];
+                        }
+                        temp = a[k,k];
+                        a[k,k] = a[kp,kp];
+                        a[kp,kp] = temp;
+                        if( kstep==2 )
+                        {
+                            temp = a[k,k+1];
+                            a[k,k+1] = a[kp,k+1];
+                            a[kp,k+1] = temp;
+                        }
+                    }
+                    k = k+kstep;
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inv(A) from the factorization A = L*D*L'.
+                //
+                // K is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = n;
+                while( k>=1 )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        a[k,k] = 1/a[k,k];
+                        
+                        //
+                        // Compute column K of the inverse.
+                        //
+                        if( k<n )
+                        {
+                            kp1 = k+1;
+                            km1 = k-1;
+                            l = n-k;
+                            i1_ = (kp1) - (1);
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, k+1, n, ref work, -1, ref work2);
+                            i1_ = (1) - (kp1);
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                a[i_,k] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                        }
+                        kstep = 1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Invert the diagonal block.
+                        //
+                        t = Math.Abs(a[k,k-1]);
+                        ak = a[k-1,k-1]/t;
+                        akp1 = a[k,k]/t;
+                        akkp1 = a[k,k-1]/t;
+                        d = t*(ak*akp1-1);
+                        a[k-1,k-1] = akp1/d;
+                        a[k,k] = ak/d;
+                        a[k,k-1] = -(akkp1/d);
+                        
+                        //
+                        // Compute columns K-1 and K of the inverse.
+                        //
+                        if( k<n )
+                        {
+                            kp1 = k+1;
+                            km1 = k-1;
+                            l = n-k;
+                            i1_ = (kp1) - (1);
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, k+1, n, ref work, -1, ref work2);
+                            i1_ = (1) - (kp1);
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                a[i_,k] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k,k] = a[k,k]-v;
+                            v = 0.0;
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                v += a[i_,k]*a[i_,km1];
+                            }
+                            a[k,k-1] = a[k,k-1]-v;
+                            i1_ = (kp1) - (1);
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                work[i_] = a[i_+i1_,km1];
+                            }
+                            sblas.symmetricmatrixvectormultiply(ref a, isupper, k+1, n, ref work, -1, ref work2);
+                            i1_ = (1) - (kp1);
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                a[i_,km1] = work2[i_+i1_];
+                            }
+                            v = 0.0;
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                v += work[i_]*work2[i_];
+                            }
+                            a[k-1,k-1] = a[k-1,k-1]-v;
+                        }
+                        kstep = 2;
+                    }
+                    kp = Math.Abs(pivots[k]);
+                    if( kp!=k )
+                    {
+                        
+                        //
+                        // Interchange rows and columns K and KP in the trailing
+                        // submatrix A(k-1:n,k-1:n)
+                        //
+                        if( kp<n )
+                        {
+                            l = n-kp;
+                            kp1 = kp+1;
+                            i1_ = (kp1) - (1);
+                            for(i_=1; i_<=l;i_++)
+                            {
+                                work[i_] = a[i_+i1_,k];
+                            }
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                a[i_,k] = a[i_,kp];
+                            }
+                            i1_ = (1) - (kp1);
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                a[i_,kp] = work[i_+i1_];
+                            }
+                        }
+                        l = kp-k-1;
+                        i1 = k+1;
+                        i2 = kp-1;
+                        i1_ = (i1) - (1);
+                        for(i_=1; i_<=l;i_++)
+                        {
+                            work[i_] = a[i_+i1_,k];
+                        }
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            a[i_,k] = a[kp,i_];
+                        }
+                        i1_ = (1) - (i1);
+                        for(i_=i1; i_<=i2;i_++)
+                        {
+                            a[kp,i_] = work[i_+i1_];
+                        }
+                        temp = a[k,k];
+                        a[k,k] = a[kp,kp];
+                        a[kp,kp] = temp;
+                        if( kstep==2 )
+                        {
+                            temp = a[k,k-1];
+                            a[k,k-1] = a[kp,k-1];
+                            a[kp,k-1] = temp;
+                        }
+                    }
+                    k = k-kstep;
+                }
+            }
+            return result;
+        }
+
+
+        public static bool inversesymmetricindefinite(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            ldlt.ldltdecomposition(ref a, n, isupper, ref pivots);
+            result = inverseldlt(ref a, ref pivots, n, isupper);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spddet.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spddet.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spddet.cs	(revision 2645)
@@ -0,0 +1,132 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spddet
+    {
+        /*************************************************************************
+        Determinant calculation of the matrix given by the Cholesky decomposition.
+
+        Input parameters:
+            A   -   Cholesky decomposition,
+                    output of SMatrixCholesky subroutine.
+            N   -   size of matrix A.
+
+        As the determinant is equal to the product of squares of diagonal elements,
+        its not necessary to specify which triangle - lower or upper - the matrix
+        is stored in.
+
+        Result:
+            matrix determinant.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double spdmatrixcholeskydet(ref double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+
+            result = 1;
+            for(i=0; i<=n-1; i++)
+            {
+                result = result*AP.Math.Sqr(a[i,i]);
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Determinant calculation of the symmetric positive definite matrix.
+
+        Input parameters:
+            A       -   matrix. Array with elements [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   if IsUpper = True, then the symmetric matrix A is given by
+                        its upper triangle, and the lower triangle isnt used by
+                        subroutine. Similarly, if IsUpper = False, then A is given
+                        by its lower triangle.
+
+        Result:
+            determinant of matrix A.
+            If matrix A is not positive definite, then subroutine returns -1.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static double spdmatrixdet(double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+
+            a = (double[,])a.Clone();
+
+            if( !cholesky.spdmatrixcholesky(ref a, n, isupper) )
+            {
+                result = -1;
+            }
+            else
+            {
+                result = spdmatrixcholeskydet(ref a, n);
+            }
+            return result;
+        }
+
+
+        public static double determinantcholesky(ref double[,] a,
+            int n)
+        {
+            double result = 0;
+            int i = 0;
+
+            result = 1;
+            for(i=1; i<=n; i++)
+            {
+                result = result*AP.Math.Sqr(a[i,i]);
+            }
+            return result;
+        }
+
+
+        public static double determinantspd(double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+
+            a = (double[,])a.Clone();
+
+            if( !cholesky.choleskydecomposition(ref a, n, isupper) )
+            {
+                result = -1;
+            }
+            else
+            {
+                result = determinantcholesky(ref a, n);
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdgevd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdgevd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdgevd.cs	(revision 2645)
@@ -0,0 +1,950 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spdgevd
+    {
+        /*************************************************************************
+        Algorithm for solving the following generalized symmetric positive-definite
+        eigenproblem:
+            A*x = lambda*B*x (1) or
+            A*B*x = lambda*x (2) or
+            B*A*x = lambda*x (3).
+        where A is a symmetric matrix, B - symmetric positive-definite matrix.
+        The problem is solved by reducing it to an ordinary  symmetric  eigenvalue
+        problem.
+
+        Input parameters:
+            A           -   symmetric matrix which is given by its upper or lower
+                            triangular part.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            N           -   size of matrices A and B.
+            IsUpperA    -   storage format of matrix A.
+            B           -   symmetric positive-definite matrix which is given by
+                            its upper or lower triangular part.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            IsUpperB    -   storage format of matrix B.
+            ZNeeded     -   if ZNeeded is equal to:
+                             * 0, the eigenvectors are not returned;
+                             * 1, the eigenvectors are returned.
+            ProblemType -   if ProblemType is equal to:
+                             * 1, the following problem is solved: A*x = lambda*B*x;
+                             * 2, the following problem is solved: A*B*x = lambda*x;
+                             * 3, the following problem is solved: B*A*x = lambda*x.
+
+        Output parameters:
+            D           -   eigenvalues in ascending order.
+                            Array whose index ranges within [0..N-1].
+            Z           -   if ZNeeded is equal to:
+                             * 0, Z hasnt changed;
+                             * 1, Z contains eigenvectors.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+                            The eigenvectors are stored in matrix columns. It should
+                            be noted that the eigenvectors in such problems do not
+                            form an orthogonal system.
+
+        Result:
+            True, if the problem was solved successfully.
+            False, if the error occurred during the Cholesky decomposition of matrix
+            B (the matrix isnt positive-definite) or during the work of the iterative
+            algorithm for solving the symmetric eigenproblem.
+
+        See also the GeneralizedSymmetricDefiniteEVDReduce subroutine.
+
+          -- ALGLIB --
+             Copyright 1.28.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixgevd(double[,] a,
+            int n,
+            bool isuppera,
+            ref double[,] b,
+            bool isupperb,
+            int zneeded,
+            int problemtype,
+            ref double[] d,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[,] r = new double[0,0];
+            double[,] t = new double[0,0];
+            bool isupperr = new bool();
+            int j1 = 0;
+            int j2 = 0;
+            int j1inc = 0;
+            int j2inc = 0;
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            int i_ = 0;
+
+            a = (double[,])a.Clone();
+
+            
+            //
+            // Reduce and solve
+            //
+            result = smatrixgevdreduce(ref a, n, isuppera, ref b, isupperb, problemtype, ref r, ref isupperr);
+            if( !result )
+            {
+                return result;
+            }
+            result = sevd.smatrixevd(a, n, zneeded, isuppera, ref d, ref t);
+            if( !result )
+            {
+                return result;
+            }
+            
+            //
+            // Transform eigenvectors if needed
+            //
+            if( zneeded!=0 )
+            {
+                
+                //
+                // fill Z with zeros
+                //
+                z = new double[n-1+1, n-1+1];
+                for(j=0; j<=n-1; j++)
+                {
+                    z[0,j] = 0.0;
+                }
+                for(i=1; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        z[i,i_] = z[0,i_];
+                    }
+                }
+                
+                //
+                // Setup R properties
+                //
+                if( isupperr )
+                {
+                    j1 = 0;
+                    j2 = n-1;
+                    j1inc = +1;
+                    j2inc = 0;
+                }
+                else
+                {
+                    j1 = 0;
+                    j2 = 0;
+                    j1inc = 0;
+                    j2inc = +1;
+                }
+                
+                //
+                // Calculate R*Z
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    for(j=j1; j<=j2; j++)
+                    {
+                        v = r[i,j];
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            z[i,i_] = z[i,i_] + v*t[j,i_];
+                        }
+                    }
+                    j1 = j1+j1inc;
+                    j2 = j2+j2inc;
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Algorithm for reduction of the following generalized symmetric positive-
+        definite eigenvalue problem:
+            A*x = lambda*B*x (1) or
+            A*B*x = lambda*x (2) or
+            B*A*x = lambda*x (3)
+        to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and
+        the given problems are the same, and the eigenvectors of the given problem
+        could be obtained by multiplying the obtained eigenvectors by the
+        transformation matrix x = R*y).
+
+        Here A is a symmetric matrix, B - symmetric positive-definite matrix.
+
+        Input parameters:
+            A           -   symmetric matrix which is given by its upper or lower
+                            triangular part.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            N           -   size of matrices A and B.
+            IsUpperA    -   storage format of matrix A.
+            B           -   symmetric positive-definite matrix which is given by
+                            its upper or lower triangular part.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            IsUpperB    -   storage format of matrix B.
+            ProblemType -   if ProblemType is equal to:
+                             * 1, the following problem is solved: A*x = lambda*B*x;
+                             * 2, the following problem is solved: A*B*x = lambda*x;
+                             * 3, the following problem is solved: B*A*x = lambda*x.
+
+        Output parameters:
+            A           -   symmetric matrix which is given by its upper or lower
+                            triangle depending on IsUpperA. Contains matrix C.
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            R           -   upper triangular or low triangular transformation matrix
+                            which is used to obtain the eigenvectors of a given problem
+                            as the product of eigenvectors of C (from the right) and
+                            matrix R (from the left). If the matrix is upper
+                            triangular, the elements below the main diagonal
+                            are equal to 0 (and vice versa). Thus, we can perform
+                            the multiplication without taking into account the
+                            internal structure (which is an easier though less
+                            effective way).
+                            Array whose indexes range within [0..N-1, 0..N-1].
+            IsUpperR    -   type of matrix R (upper or lower triangular).
+
+        Result:
+            True, if the problem was reduced successfully.
+            False, if the error occurred during the Cholesky decomposition of
+                matrix B (the matrix is not positive-definite).
+
+          -- ALGLIB --
+             Copyright 1.28.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixgevdreduce(ref double[,] a,
+            int n,
+            bool isuppera,
+            ref double[,] b,
+            bool isupperb,
+            int problemtype,
+            ref double[,] r,
+            ref bool isupperr)
+        {
+            bool result = new bool();
+            double[,] t = new double[0,0];
+            double[] w1 = new double[0];
+            double[] w2 = new double[0];
+            double[] w3 = new double[0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "SMatrixGEVDReduce: N<=0!");
+            System.Diagnostics.Debug.Assert(problemtype==1 | problemtype==2 | problemtype==3, "SMatrixGEVDReduce: incorrect ProblemType!");
+            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 = new double[n-1+1, n-1+1];
+                if( isupperb )
+                {
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            t[i_,i] = b[i,i_];
+                        }
+                    }
+                }
+                else
+                {
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            t[i,i_] = b[i,i_];
+                        }
+                    }
+                }
+                if( !cholesky.spdmatrixcholesky(ref t, n, false) )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Invert L in T
+                //
+                if( !trinverse.rmatrixtrinverse(ref t, n, false, false) )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Build L^(-1) * A * L^(-T) in R
+                //
+                w1 = new double[n+1];
+                w2 = new double[n+1];
+                r = new double[n-1+1, n-1+1];
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Form w2 = A * l'(j) (here l'(j) is j-th column of L^(-T))
+                    //
+                    i1_ = (0) - (1);
+                    for(i_=1; i_<=j;i_++)
+                    {
+                        w1[i_] = t[j-1,i_+i1_];
+                    }
+                    sblas.symmetricmatrixvectormultiply(ref a, isuppera, 0, j-1, ref w1, 1.0, ref w2);
+                    if( isuppera )
+                    {
+                        blas.matrixvectormultiply(ref a, 0, j-1, j, n-1, true, ref w1, 1, j, 1.0, ref w2, j+1, n, 0.0);
+                    }
+                    else
+                    {
+                        blas.matrixvectormultiply(ref a, j, n-1, 0, j-1, false, ref w1, 1, j, 1.0, ref w2, j+1, n, 0.0);
+                    }
+                    
+                    //
+                    // Form l(i)*w2 (here l(i) is i-th row of L^(-1))
+                    //
+                    for(i=1; i<=n; i++)
+                    {
+                        i1_ = (1)-(0);
+                        v = 0.0;
+                        for(i_=0; i_<=i-1;i_++)
+                        {
+                            v += t[i-1,i_]*w2[i_+i1_];
+                        }
+                        r[i-1,j-1] = v;
+                    }
+                }
+                
+                //
+                // Copy R to A
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        a[i,i_] = r[i,i_];
+                    }
+                }
+                
+                //
+                // Copy L^(-1) from T to R and transpose
+                //
+                isupperr = true;
+                for(i=0; i<=n-1; i++)
+                {
+                    for(j=0; j<=i-1; j++)
+                    {
+                        r[i,j] = 0;
+                    }
+                }
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=i; i_<=n-1;i_++)
+                    {
+                        r[i,i_] = t[i_,i];
+                    }
+                }
+                return result;
+            }
+            
+            //
+            // Problem 2:  A*B*x = lambda*x
+            // or
+            // problem 3:  B*A*x = lambda*x
+            //
+            // Reducing to:
+            //     C*y = lambda*y
+            //     C = U * A * U'
+            //     B = U'* U
+            //
+            if( problemtype==2 | problemtype==3 )
+            {
+                
+                //
+                // Factorize B in T: B = U'*U
+                //
+                t = new double[n-1+1, n-1+1];
+                if( isupperb )
+                {
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            t[i,i_] = b[i,i_];
+                        }
+                    }
+                }
+                else
+                {
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            t[i,i_] = b[i_,i];
+                        }
+                    }
+                }
+                if( !cholesky.spdmatrixcholesky(ref t, n, true) )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Build U * A * U' in R
+                //
+                w1 = new double[n+1];
+                w2 = new double[n+1];
+                w3 = new double[n+1];
+                r = new double[n-1+1, n-1+1];
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Form w2 = A * u'(j) (here u'(j) is j-th column of U')
+                    //
+                    i1_ = (j-1) - (1);
+                    for(i_=1; i_<=n-j+1;i_++)
+                    {
+                        w1[i_] = t[j-1,i_+i1_];
+                    }
+                    sblas.symmetricmatrixvectormultiply(ref a, isuppera, j-1, n-1, ref w1, 1.0, ref w3);
+                    i1_ = (1) - (j);
+                    for(i_=j; i_<=n;i_++)
+                    {
+                        w2[i_] = w3[i_+i1_];
+                    }
+                    i1_ = (j-1) - (j);
+                    for(i_=j; i_<=n;i_++)
+                    {
+                        w1[i_] = t[j-1,i_+i1_];
+                    }
+                    if( isuppera )
+                    {
+                        blas.matrixvectormultiply(ref a, 0, j-2, j-1, n-1, false, ref w1, j, n, 1.0, ref w2, 1, j-1, 0.0);
+                    }
+                    else
+                    {
+                        blas.matrixvectormultiply(ref a, j-1, n-1, 0, j-2, true, ref w1, j, n, 1.0, ref w2, 1, j-1, 0.0);
+                    }
+                    
+                    //
+                    // Form u(i)*w2 (here u(i) is i-th row of U)
+                    //
+                    for(i=1; i<=n; i++)
+                    {
+                        i1_ = (i)-(i-1);
+                        v = 0.0;
+                        for(i_=i-1; i_<=n-1;i_++)
+                        {
+                            v += t[i-1,i_]*w2[i_+i1_];
+                        }
+                        r[i-1,j-1] = v;
+                    }
+                }
+                
+                //
+                // Copy R to A
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        a[i,i_] = r[i,i_];
+                    }
+                }
+                if( problemtype==2 )
+                {
+                    
+                    //
+                    // Invert U in T
+                    //
+                    if( !trinverse.rmatrixtrinverse(ref t, n, true, false) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    
+                    //
+                    // Copy U^-1 from T to R
+                    //
+                    isupperr = true;
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(j=0; j<=i-1; j++)
+                        {
+                            r[i,j] = 0;
+                        }
+                    }
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            r[i,i_] = t[i,i_];
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // Copy U from T to R and transpose
+                    //
+                    isupperr = false;
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(j=i+1; j<=n-1; j++)
+                        {
+                            r[i,j] = 0;
+                        }
+                    }
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            r[i_,i] = t[i,i_];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool generalizedsymmetricdefiniteevd(double[,] a,
+            int n,
+            bool isuppera,
+            ref double[,] b,
+            bool isupperb,
+            int zneeded,
+            int problemtype,
+            ref double[] d,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[,] r = new double[0,0];
+            double[,] t = new double[0,0];
+            bool isupperr = new bool();
+            int j1 = 0;
+            int j2 = 0;
+            int j1inc = 0;
+            int j2inc = 0;
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            int i_ = 0;
+
+            a = (double[,])a.Clone();
+
+            
+            //
+            // Reduce and solve
+            //
+            result = generalizedsymmetricdefiniteevdreduce(ref a, n, isuppera, ref b, isupperb, problemtype, ref r, ref isupperr);
+            if( !result )
+            {
+                return result;
+            }
+            result = sevd.symmetricevd(a, n, zneeded, isuppera, ref d, ref t);
+            if( !result )
+            {
+                return result;
+            }
+            
+            //
+            // Transform eigenvectors if needed
+            //
+            if( zneeded!=0 )
+            {
+                
+                //
+                // fill Z with zeros
+                //
+                z = new double[n+1, n+1];
+                for(j=1; j<=n; j++)
+                {
+                    z[1,j] = 0.0;
+                }
+                for(i=2; i<=n; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z[i,i_] = z[1,i_];
+                    }
+                }
+                
+                //
+                // Setup R properties
+                //
+                if( isupperr )
+                {
+                    j1 = 1;
+                    j2 = n;
+                    j1inc = +1;
+                    j2inc = 0;
+                }
+                else
+                {
+                    j1 = 1;
+                    j2 = 1;
+                    j1inc = 0;
+                    j2inc = +1;
+                }
+                
+                //
+                // Calculate R*Z
+                //
+                for(i=1; i<=n; i++)
+                {
+                    for(j=j1; j<=j2; j++)
+                    {
+                        v = r[i,j];
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            z[i,i_] = z[i,i_] + v*t[j,i_];
+                        }
+                    }
+                    j1 = j1+j1inc;
+                    j2 = j2+j2inc;
+                }
+            }
+            return result;
+        }
+
+
+        public static bool generalizedsymmetricdefiniteevdreduce(ref double[,] a,
+            int n,
+            bool isuppera,
+            ref double[,] b,
+            bool isupperb,
+            int problemtype,
+            ref double[,] r,
+            ref bool isupperr)
+        {
+            bool result = new bool();
+            double[,] t = new double[0,0];
+            double[] w1 = new double[0];
+            double[] w2 = new double[0];
+            double[] w3 = new double[0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>0, "GeneralizedSymmetricDefiniteEVDReduce: N<=0!");
+            System.Diagnostics.Debug.Assert(problemtype==1 | problemtype==2 | problemtype==3, "GeneralizedSymmetricDefiniteEVDReduce: incorrect ProblemType!");
+            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 = new double[n+1, n+1];
+                if( isupperb )
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            t[i_,i] = b[i,i_];
+                        }
+                    }
+                }
+                else
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            t[i,i_] = b[i,i_];
+                        }
+                    }
+                }
+                if( !cholesky.choleskydecomposition(ref t, n, false) )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Invert L in T
+                //
+                if( !trinverse.invtriangular(ref t, n, false, false) )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Build L^(-1) * A * L^(-T) in R
+                //
+                w1 = new double[n+1];
+                w2 = new double[n+1];
+                r = new double[n+1, n+1];
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Form w2 = A * l'(j) (here l'(j) is j-th column of L^(-T))
+                    //
+                    for(i_=1; i_<=j;i_++)
+                    {
+                        w1[i_] = t[j,i_];
+                    }
+                    sblas.symmetricmatrixvectormultiply(ref a, isuppera, 1, j, ref w1, 1.0, ref w2);
+                    if( isuppera )
+                    {
+                        blas.matrixvectormultiply(ref a, 1, j, j+1, n, true, ref w1, 1, j, 1.0, ref w2, j+1, n, 0.0);
+                    }
+                    else
+                    {
+                        blas.matrixvectormultiply(ref a, j+1, n, 1, j, false, ref w1, 1, j, 1.0, ref w2, j+1, n, 0.0);
+                    }
+                    
+                    //
+                    // Form l(i)*w2 (here l(i) is i-th row of L^(-1))
+                    //
+                    for(i=1; i<=n; i++)
+                    {
+                        v = 0.0;
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            v += t[i,i_]*w2[i_];
+                        }
+                        r[i,j] = v;
+                    }
+                }
+                
+                //
+                // Copy R to A
+                //
+                for(i=1; i<=n; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        a[i,i_] = r[i,i_];
+                    }
+                }
+                
+                //
+                // Copy L^(-1) from T to R and transpose
+                //
+                isupperr = true;
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=i-1; j++)
+                    {
+                        r[i,j] = 0;
+                    }
+                }
+                for(i=1; i<=n; i++)
+                {
+                    for(i_=i; i_<=n;i_++)
+                    {
+                        r[i,i_] = t[i_,i];
+                    }
+                }
+                return result;
+            }
+            
+            //
+            // Problem 2:  A*B*x = lambda*x
+            // or
+            // problem 3:  B*A*x = lambda*x
+            //
+            // Reducing to:
+            //     C*y = lambda*y
+            //     C = U * A * U'
+            //     B = U'* U
+            //
+            if( problemtype==2 | problemtype==3 )
+            {
+                
+                //
+                // Factorize B in T: B = U'*U
+                //
+                t = new double[n+1, n+1];
+                if( isupperb )
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            t[i,i_] = b[i,i_];
+                        }
+                    }
+                }
+                else
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            t[i,i_] = b[i_,i];
+                        }
+                    }
+                }
+                if( !cholesky.choleskydecomposition(ref t, n, true) )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Build U * A * U' in R
+                //
+                w1 = new double[n+1];
+                w2 = new double[n+1];
+                w3 = new double[n+1];
+                r = new double[n+1, n+1];
+                for(j=1; j<=n; j++)
+                {
+                    
+                    //
+                    // Form w2 = A * u'(j) (here u'(j) is j-th column of U')
+                    //
+                    i1_ = (j) - (1);
+                    for(i_=1; i_<=n-j+1;i_++)
+                    {
+                        w1[i_] = t[j,i_+i1_];
+                    }
+                    sblas.symmetricmatrixvectormultiply(ref a, isuppera, j, n, ref w1, 1.0, ref w3);
+                    i1_ = (1) - (j);
+                    for(i_=j; i_<=n;i_++)
+                    {
+                        w2[i_] = w3[i_+i1_];
+                    }
+                    for(i_=j; i_<=n;i_++)
+                    {
+                        w1[i_] = t[j,i_];
+                    }
+                    if( isuppera )
+                    {
+                        blas.matrixvectormultiply(ref a, 1, j-1, j, n, false, ref w1, j, n, 1.0, ref w2, 1, j-1, 0.0);
+                    }
+                    else
+                    {
+                        blas.matrixvectormultiply(ref a, j, n, 1, j-1, true, ref w1, j, n, 1.0, ref w2, 1, j-1, 0.0);
+                    }
+                    
+                    //
+                    // Form u(i)*w2 (here u(i) is i-th row of U)
+                    //
+                    for(i=1; i<=n; i++)
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            v += t[i,i_]*w2[i_];
+                        }
+                        r[i,j] = v;
+                    }
+                }
+                
+                //
+                // Copy R to A
+                //
+                for(i=1; i<=n; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        a[i,i_] = r[i,i_];
+                    }
+                }
+                if( problemtype==2 )
+                {
+                    
+                    //
+                    // Invert U in T
+                    //
+                    if( !trinverse.invtriangular(ref t, n, true, false) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    
+                    //
+                    // Copy U^-1 from T to R
+                    //
+                    isupperr = true;
+                    for(i=1; i<=n; i++)
+                    {
+                        for(j=1; j<=i-1; j++)
+                        {
+                            r[i,j] = 0;
+                        }
+                    }
+                    for(i=1; i<=n; i++)
+                    {
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            r[i,i_] = t[i,i_];
+                        }
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // Copy U from T to R and transpose
+                    //
+                    isupperr = false;
+                    for(i=1; i<=n; i++)
+                    {
+                        for(j=i+1; j<=n; j++)
+                        {
+                            r[i,j] = 0;
+                        }
+                    }
+                    for(i=1; i<=n; i++)
+                    {
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            r[i_,i] = t[i,i_];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdinverse.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdinverse.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdinverse.cs	(revision 2645)
@@ -0,0 +1,472 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spdinverse
+    {
+        /*************************************************************************
+        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  CholeskyDecomposition subroutine.
+                        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 as A = U'*U
+                        (matrix contains upper triangle).
+                        Similarly, if IsUpper = False, then A = L*L'.
+
+        Output parameters:
+            A       -   upper or lower triangle of symmetric matrix A^-1, depending
+                        on the value of IsUpper.
+
+        Result:
+            True, if the inversion succeeded.
+            False, if matrix A contains zero elements on its main diagonal.
+            Matrix A could not be inverted.
+
+        The algorithm is the modification of DPOTRI and DLAUU2 subroutines from
+        LAPACK library.
+        *************************************************************************/
+        public static bool spdmatrixcholeskyinverse(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            double v = 0;
+            double ajj = 0;
+            double aii = 0;
+            double[] t = new double[0];
+            double[,] a1 = new double[0,0];
+            int i_ = 0;
+
+            result = true;
+            
+            //
+            // Test the input parameters.
+            //
+            t = new double[n-1+1];
+            if( isupper )
+            {
+                
+                //
+                // Compute inverse of upper triangular matrix.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    if( (double)(a[j,j])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    a[j,j] = 1/a[j,j];
+                    ajj = -a[j,j];
+                    
+                    //
+                    // Compute elements 1:j-1 of j-th column.
+                    //
+                    for(i_=0; i_<=j-1;i_++)
+                    {
+                        t[i_] = a[i_,j];
+                    }
+                    for(i=0; i<=j-1; i++)
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=j-1;i_++)
+                        {
+                            v += a[i,i_]*t[i_];
+                        }
+                        a[i,j] = v;
+                    }
+                    for(i_=0; i_<=j-1;i_++)
+                    {
+                        a[i_,j] = ajj*a[i_,j];
+                    }
+                }
+                
+                //
+                // InvA = InvU * InvU'
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    aii = a[i,i];
+                    if( i<n-1 )
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            v += a[i,i_]*a[i,i_];
+                        }
+                        a[i,i] = v;
+                        for(k=0; k<=i-1; k++)
+                        {
+                            v = 0.0;
+                            for(i_=i+1; i_<=n-1;i_++)
+                            {
+                                v += a[k,i_]*a[i,i_];
+                            }
+                            a[k,i] = a[k,i]*aii+v;
+                        }
+                    }
+                    else
+                    {
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            a[i_,i] = aii*a[i_,i];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inverse of lower triangular matrix.
+                //
+                for(j=n-1; j>=0; j--)
+                {
+                    if( (double)(a[j,j])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    a[j,j] = 1/a[j,j];
+                    ajj = -a[j,j];
+                    if( j<n-1 )
+                    {
+                        
+                        //
+                        // Compute elements j+1:n of j-th column.
+                        //
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=j+1+1; i<=n; i++)
+                        {
+                            v = 0.0;
+                            for(i_=j+1; i_<=i-1;i_++)
+                            {
+                                v += a[i-1,i_]*t[i_];
+                            }
+                            a[i-1,j] = v;
+                        }
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+                
+                //
+                // InvA = InvL' * InvL
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    aii = a[i,i];
+                    if( i<n-1 )
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=n-1;i_++)
+                        {
+                            v += a[i_,i]*a[i_,i];
+                        }
+                        a[i,i] = v;
+                        for(k=0; k<=i-1; k++)
+                        {
+                            v = 0.0;
+                            for(i_=i+1; i_<=n-1;i_++)
+                            {
+                                v += a[i_,k]*a[i_,i];
+                            }
+                            a[i,k] = aii*a[i,k]+v;
+                        }
+                    }
+                    else
+                    {
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            a[i,i_] = aii*a[i,i_];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        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.
+            IsUpper -   storage format.
+                        If IsUpper = True, then the upper triangle of matrix A is
+                        given, otherwise the lower triangle is given.
+
+        Output parameters:
+            A       -   inverse of matrix A.
+                        Array with elements [0..N-1,0..N-1].
+                        If IsUpper = True, then the upper triangle of matrix A^-1
+                        is used, and the elements below the main diagonal are not
+                        used nor changed. The same applies if IsUpper = False.
+
+        Result:
+            True, if the matrix is positive definite.
+            False, if the matrix is not positive definite (and it could not be
+            inverted by this algorithm).
+        *************************************************************************/
+        public static bool spdmatrixinverse(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+
+            result = false;
+            if( cholesky.spdmatrixcholesky(ref a, n, isupper) )
+            {
+                if( spdmatrixcholeskyinverse(ref a, n, isupper) )
+                {
+                    result = true;
+                }
+            }
+            return result;
+        }
+
+
+        public static bool inversecholesky(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int nmj = 0;
+            int jm1 = 0;
+            int jp1 = 0;
+            int ip1 = 0;
+            double v = 0;
+            double ajj = 0;
+            double aii = 0;
+            double[] t = new double[0];
+            double[] d = new double[0];
+            int i_ = 0;
+
+            result = true;
+            
+            //
+            // Test the input parameters.
+            //
+            t = new double[n+1];
+            d = new double[n+1];
+            if( isupper )
+            {
+                
+                //
+                // Compute inverse of upper triangular matrix.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    if( (double)(a[j,j])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    jm1 = j-1;
+                    a[j,j] = 1/a[j,j];
+                    ajj = -a[j,j];
+                    
+                    //
+                    // Compute elements 1:j-1 of j-th column.
+                    //
+                    for(i_=1; i_<=jm1;i_++)
+                    {
+                        t[i_] = a[i_,j];
+                    }
+                    for(i=1; i<=j-1; i++)
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=jm1;i_++)
+                        {
+                            v += a[i,i_]*a[i_,j];
+                        }
+                        a[i,j] = v;
+                    }
+                    for(i_=1; i_<=jm1;i_++)
+                    {
+                        a[i_,j] = ajj*a[i_,j];
+                    }
+                }
+                
+                //
+                // InvA = InvU * InvU'
+                //
+                for(i=1; i<=n; i++)
+                {
+                    aii = a[i,i];
+                    if( i<n )
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            v += a[i,i_]*a[i,i_];
+                        }
+                        a[i,i] = v;
+                        ip1 = i+1;
+                        for(k=1; k<=i-1; k++)
+                        {
+                            v = 0.0;
+                            for(i_=ip1; i_<=n;i_++)
+                            {
+                                v += a[k,i_]*a[i,i_];
+                            }
+                            a[k,i] = a[k,i]*aii+v;
+                        }
+                    }
+                    else
+                    {
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            a[i_,i] = aii*a[i_,i];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inverse of lower triangular matrix.
+                //
+                for(j=n; j>=1; j--)
+                {
+                    if( (double)(a[j,j])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                    a[j,j] = 1/a[j,j];
+                    ajj = -a[j,j];
+                    if( j<n )
+                    {
+                        
+                        //
+                        // Compute elements j+1:n of j-th column.
+                        //
+                        nmj = n-j;
+                        jp1 = j+1;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=j+1; i<=n; i++)
+                        {
+                            v = 0.0;
+                            for(i_=jp1; i_<=i;i_++)
+                            {
+                                v += a[i,i_]*t[i_];
+                            }
+                            a[i,j] = v;
+                        }
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+                
+                //
+                // InvA = InvL' * InvL
+                //
+                for(i=1; i<=n; i++)
+                {
+                    aii = a[i,i];
+                    if( i<n )
+                    {
+                        v = 0.0;
+                        for(i_=i; i_<=n;i_++)
+                        {
+                            v += a[i_,i]*a[i_,i];
+                        }
+                        a[i,i] = v;
+                        ip1 = i+1;
+                        for(k=1; k<=i-1; k++)
+                        {
+                            v = 0.0;
+                            for(i_=ip1; i_<=n;i_++)
+                            {
+                                v += a[i_,k]*a[i_,i];
+                            }
+                            a[i,k] = aii*a[i,k]+v;
+                        }
+                    }
+                    else
+                    {
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            a[i,i_] = aii*a[i,i_];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool inversesymmetricpositivedefinite(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            bool result = new bool();
+
+            result = false;
+            if( cholesky.choleskydecomposition(ref a, n, isupper) )
+            {
+                if( inversecholesky(ref a, n, isupper) )
+                {
+                    result = true;
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdrcond.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdrcond.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdrcond.cs	(revision 2645)
@@ -0,0 +1,430 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spdrcond
+    {
+        /*************************************************************************
+        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.
+        *************************************************************************/
+        public static double spdmatrixrcond(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            double[,] a1 = new double[0,0];
+            int i = 0;
+            int j = 0;
+            int im = 0;
+            int jm = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                if( isupper )
+                {
+                    for(j=i; j<=n; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+                else
+                {
+                    for(j=1; j<=i; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+            }
+            nrm = 0;
+            for(j=1; j<=n; j++)
+            {
+                v = 0;
+                for(i=1; i<=n; i++)
+                {
+                    im = i;
+                    jm = j;
+                    if( isupper & j<i )
+                    {
+                        im = j;
+                        jm = i;
+                    }
+                    if( !isupper & j>i )
+                    {
+                        im = j;
+                        jm = i;
+                    }
+                    v = v+Math.Abs(a1[im,jm]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            if( cholesky.choleskydecomposition(ref a1, n, isupper) )
+            {
+                internalcholeskyrcond(ref a1, n, isupper, true, nrm, ref v);
+                result = v;
+            }
+            else
+            {
+                result = -1;
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Condition number estimate of a symmetric positive definite matrix given by
+        Cholesky decomposition.
+
+        The algorithm calculates a lower bound of the condition number. In this
+        case, the algorithm does not return a lower bound of the condition number,
+        but an inverse number (to avoid an overflow in case of a singular matrix).
+
+        It should be noted that 1-norm and inf-norm condition numbers of symmetric
+        matrices are equal, so the algorithm doesn't take into account the
+        differences between these types of norms.
+
+        Input parameters:
+            CD  - Cholesky decomposition of matrix A,
+                  output of SMatrixCholesky subroutine.
+            N   - size of matrix A.
+
+        Result: 1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double spdmatrixcholeskyrcond(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            double[,] a1 = new double[0,0];
+            int i = 0;
+            int j = 0;
+            double v = 0;
+
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                if( isupper )
+                {
+                    for(j=i; j<=n; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+                else
+                {
+                    for(j=1; j<=i; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+            }
+            internalcholeskyrcond(ref a1, n, isupper, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double rcondspd(double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            int im = 0;
+            int jm = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            nrm = 0;
+            for(j=1; j<=n; j++)
+            {
+                v = 0;
+                for(i=1; i<=n; i++)
+                {
+                    im = i;
+                    jm = j;
+                    if( isupper & j<i )
+                    {
+                        im = j;
+                        jm = i;
+                    }
+                    if( !isupper & j>i )
+                    {
+                        im = j;
+                        jm = i;
+                    }
+                    v = v+Math.Abs(a[im,jm]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            if( cholesky.choleskydecomposition(ref a, n, isupper) )
+            {
+                internalcholeskyrcond(ref a, n, isupper, true, nrm, ref v);
+                result = v;
+            }
+            else
+            {
+                result = -1;
+            }
+            return result;
+        }
+
+
+        public static double rcondcholesky(ref double[,] cd,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            double v = 0;
+
+            internalcholeskyrcond(ref cd, n, isupper, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static void internalcholeskyrcond(ref double[,] chfrm,
+            int n,
+            bool isupper,
+            bool isnormprovided,
+            double anorm,
+            ref double rcond)
+        {
+            bool normin = new bool();
+            int i = 0;
+            int ix = 0;
+            int kase = 0;
+            double ainvnm = 0;
+            double scl = 0;
+            double scalel = 0;
+            double scaleu = 0;
+            double smlnum = 0;
+            double[] work0 = new double[0];
+            double[] work1 = new double[0];
+            double[] work2 = new double[0];
+            int[] iwork = new int[0];
+            double v = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=0);
+            
+            //
+            // Estimate the norm of A.
+            //
+            if( !isnormprovided )
+            {
+                kase = 0;
+                anorm = 0;
+                while( true )
+                {
+                    estnorm.iterativeestimate1norm(n, ref work1, ref work0, ref iwork, ref anorm, ref kase);
+                    if( kase==0 )
+                    {
+                        break;
+                    }
+                    if( isupper )
+                    {
+                        
+                        //
+                        // Multiply by U
+                        //
+                        for(i=1; i<=n; i++)
+                        {
+                            v = 0.0;
+                            for(i_=i; i_<=n;i_++)
+                            {
+                                v += chfrm[i,i_]*work0[i_];
+                            }
+                            work0[i] = v;
+                        }
+                        
+                        //
+                        // Multiply by U'
+                        //
+                        for(i=n; i>=1; i--)
+                        {
+                            v = 0.0;
+                            for(i_=1; i_<=i;i_++)
+                            {
+                                v += chfrm[i_,i]*work0[i_];
+                            }
+                            work0[i] = v;
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Multiply by L'
+                        //
+                        for(i=1; i<=n; i++)
+                        {
+                            v = 0.0;
+                            for(i_=i; i_<=n;i_++)
+                            {
+                                v += chfrm[i_,i]*work0[i_];
+                            }
+                            work0[i] = v;
+                        }
+                        
+                        //
+                        // Multiply by L
+                        //
+                        for(i=n; i>=1; i--)
+                        {
+                            v = 0.0;
+                            for(i_=1; i_<=i;i_++)
+                            {
+                                v += chfrm[i,i_]*work0[i_];
+                            }
+                            work0[i] = v;
+                        }
+                    }
+                }
+            }
+            
+            //
+            // Quick return if possible
+            //
+            rcond = 0;
+            if( n==0 )
+            {
+                rcond = 1;
+                return;
+            }
+            if( (double)(anorm)==(double)(0) )
+            {
+                return;
+            }
+            smlnum = AP.Math.MinRealNumber;
+            
+            //
+            // Estimate the 1-norm of inv(A).
+            //
+            kase = 0;
+            normin = false;
+            while( true )
+            {
+                estnorm.iterativeestimate1norm(n, ref work1, ref work0, ref iwork, ref ainvnm, ref kase);
+                if( kase==0 )
+                {
+                    break;
+                }
+                if( isupper )
+                {
+                    
+                    //
+                    // Multiply by inv(U').
+                    //
+                    trlinsolve.safesolvetriangular(ref chfrm, n, ref work0, ref scalel, isupper, true, false, normin, ref work2);
+                    normin = true;
+                    
+                    //
+                    // Multiply by inv(U).
+                    //
+                    trlinsolve.safesolvetriangular(ref chfrm, n, ref work0, ref scaleu, isupper, false, false, normin, ref work2);
+                }
+                else
+                {
+                    
+                    //
+                    // Multiply by inv(L).
+                    //
+                    trlinsolve.safesolvetriangular(ref chfrm, n, ref work0, ref scalel, isupper, false, false, normin, ref work2);
+                    normin = true;
+                    
+                    //
+                    // Multiply by inv(L').
+                    //
+                    trlinsolve.safesolvetriangular(ref chfrm, n, ref work0, ref scaleu, isupper, true, false, normin, ref work2);
+                }
+                
+                //
+                // Multiply by 1/SCALE if doing so will not cause overflow.
+                //
+                scl = scalel*scaleu;
+                if( (double)(scl)!=(double)(1) )
+                {
+                    ix = 1;
+                    for(i=2; i<=n; i++)
+                    {
+                        if( (double)(Math.Abs(work0[i]))>(double)(Math.Abs(work0[ix])) )
+                        {
+                            ix = i;
+                        }
+                    }
+                    if( (double)(scl)<(double)(Math.Abs(work0[ix])*smlnum) | (double)(scl)==(double)(0) )
+                    {
+                        return;
+                    }
+                    for(i=1; i<=n; i++)
+                    {
+                        work0[i] = work0[i]/scl;
+                    }
+                }
+            }
+            
+            //
+            // Compute the estimate of the reciprocal condition number.
+            //
+            if( (double)(ainvnm)!=(double)(0) )
+            {
+                v = 1/ainvnm;
+                rcond = v/anorm;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdsolve.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdsolve.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spdsolve.cs	(revision 2645)
@@ -0,0 +1,346 @@
+/*************************************************************************
+This file is a part of ALGLIB project.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spdsolve
+    {
+        /*************************************************************************
+        Solving a system of linear equations with a system  matrix  given  by  its
+        Cholesky decomposition.
+
+        The algorithm solves systems with a square matrix only.
+
+        Input parameters:
+            A       -   Cholesky decomposition of a system matrix (the result of
+                        the SMatrixCholesky subroutine).
+            B       -   right side of a system.
+                        Array whose index ranges within [0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   points to the triangle of matrix A in which the Cholesky
+                        decomposition is stored. If IsUpper=True,  the  Cholesky
+                        decomposition has the form of U'*U, and the upper triangle
+                        of matrix A stores matrix U (in  that  case,  the  lower
+                        triangle isnt used and isnt changed by the subroutine)
+                        Similarly, if IsUpper = False, the Cholesky decomposition
+                        has the form of L*L',  and  the  lower  triangle  stores
+                        matrix L.
+
+        Output parameters:
+            X       -   solution of a system.
+                        Array whose index ranges within [0..N-1].
+
+        Result:
+            True, if the system is not singular. X contains the solution.
+            False, if the system is singular (there is a zero element on the main
+        diagonal). In this case, X doesn't contain a solution.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool spdmatrixcholeskysolve(ref double[,] a,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+            int i = 0;
+            double v = 0;
+            int i_ = 0;
+
+            b = (double[])b.Clone();
+
+            System.Diagnostics.Debug.Assert(n>0, "Error: N<=0 in SolveSystemCholesky");
+            
+            //
+            // det(A)=0?
+            //
+            result = true;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(a[i,i])==(double)(0) )
+                {
+                    result = false;
+                    return result;
+                }
+            }
+            
+            //
+            // det(A)<>0
+            //
+            x = new double[n-1+1];
+            if( isupper )
+            {
+                
+                //
+                // A = U'*U, solve U'*y = b first
+                //
+                b[0] = b[0]/a[0,0];
+                for(i=1; i<=n-1; i++)
+                {
+                    v = 0.0;
+                    for(i_=0; i_<=i-1;i_++)
+                    {
+                        v += a[i_,i]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                
+                //
+                // Solve U*x = y
+                //
+                b[n-1] = b[n-1]/a[n-1,n-1];
+                for(i=n-2; i>=0; i--)
+                {
+                    v = 0.0;
+                    for(i_=i+1; i_<=n-1;i_++)
+                    {
+                        v += a[i,i_]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    x[i_] = b[i_];
+                }
+            }
+            else
+            {
+                
+                //
+                // A = L*L', solve L'*y = b first
+                //
+                b[0] = b[0]/a[0,0];
+                for(i=1; i<=n-1; i++)
+                {
+                    v = 0.0;
+                    for(i_=0; i_<=i-1;i_++)
+                    {
+                        v += a[i,i_]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                
+                //
+                // Solve L'*x = y
+                //
+                b[n-1] = b[n-1]/a[n-1,n-1];
+                for(i=n-2; i>=0; i--)
+                {
+                    v = 0.0;
+                    for(i_=i+1; i_<=n-1;i_++)
+                    {
+                        v += a[i_,i]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                for(i_=0; i_<=n-1;i_++)
+                {
+                    x[i_] = b[i_];
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Solving a system of linear equations with  a  symmetric  positive-definite
+        matrix by using the Cholesky decomposition.
+
+        The algorithm solves a system of linear equations whose matrix is symmetric
+        and positive-definite.
+
+        Input parameters:
+            A       -   upper or lower triangle part of a symmetric system matrix.
+                        Array whose indexes range within [0..N-1, 0..N-1].
+            B       -   right side of a system.
+                        Array whose index ranges within [0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   points to the triangle of matrix A in which the matrix is stored.
+
+        Output parameters:
+            X       -   solution of a system.
+                        Array whose index ranges within [0..N-1].
+
+        Result:
+            True, if the system is not singular.
+            False, if the system is singular. In this case, X doesn't contain a
+        solution.
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool spdmatrixsolve(double[,] a,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+
+            a = (double[,])a.Clone();
+            b = (double[])b.Clone();
+
+            result = cholesky.spdmatrixcholesky(ref a, n, isupper);
+            if( !result )
+            {
+                return result;
+            }
+            result = spdmatrixcholeskysolve(ref a, b, n, isupper, ref x);
+            return result;
+        }
+
+
+        public static bool solvesystemcholesky(ref double[,] a,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+            int i = 0;
+            int im1 = 0;
+            int ip1 = 0;
+            double v = 0;
+            int i_ = 0;
+
+            b = (double[])b.Clone();
+
+            System.Diagnostics.Debug.Assert(n>0, "Error: N<=0 in SolveSystemCholesky");
+            
+            //
+            // det(A)=0?
+            //
+            result = true;
+            for(i=1; i<=n; i++)
+            {
+                if( (double)(a[i,i])==(double)(0) )
+                {
+                    result = false;
+                    return result;
+                }
+            }
+            
+            //
+            // det(A)<>0
+            //
+            x = new double[n+1];
+            if( isupper )
+            {
+                
+                //
+                // A = U'*U, solve U'*y = b first
+                //
+                b[1] = b[1]/a[1,1];
+                for(i=2; i<=n; i++)
+                {
+                    im1 = i-1;
+                    v = 0.0;
+                    for(i_=1; i_<=im1;i_++)
+                    {
+                        v += a[i_,i]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                
+                //
+                // Solve U*x = y
+                //
+                b[n] = b[n]/a[n,n];
+                for(i=n-1; i>=1; i--)
+                {
+                    ip1 = i+1;
+                    v = 0.0;
+                    for(i_=ip1; i_<=n;i_++)
+                    {
+                        v += a[i,i_]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                for(i_=1; i_<=n;i_++)
+                {
+                    x[i_] = b[i_];
+                }
+            }
+            else
+            {
+                
+                //
+                // A = L*L', solve L'*y = b first
+                //
+                b[1] = b[1]/a[1,1];
+                for(i=2; i<=n; i++)
+                {
+                    im1 = i-1;
+                    v = 0.0;
+                    for(i_=1; i_<=im1;i_++)
+                    {
+                        v += a[i,i_]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                
+                //
+                // Solve L'*x = y
+                //
+                b[n] = b[n]/a[n,n];
+                for(i=n-1; i>=1; i--)
+                {
+                    ip1 = i+1;
+                    v = 0.0;
+                    for(i_=ip1; i_<=n;i_++)
+                    {
+                        v += a[i_,i]*b[i_];
+                    }
+                    b[i] = (b[i]-v)/a[i,i];
+                }
+                for(i_=1; i_<=n;i_++)
+                {
+                    x[i_] = b[i_];
+                }
+            }
+            return result;
+        }
+
+
+        public static bool solvespdsystem(double[,] a,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+
+            a = (double[,])a.Clone();
+            b = (double[])b.Clone();
+
+            result = cholesky.choleskydecomposition(ref a, n, isupper);
+            if( !result )
+            {
+                return result;
+            }
+            result = solvesystemcholesky(ref a, b, n, isupper, ref x);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline1d.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline1d.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline1d.cs	(revision 2645)
@@ -0,0 +1,1824 @@
+/*************************************************************************
+Copyright (c) 2006-2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spline1d
+    {
+        /*************************************************************************
+        1-dimensional spline inteprolant
+        *************************************************************************/
+        public struct spline1dinterpolant
+        {
+            public int n;
+            public int k;
+            public double[] x;
+            public double[] c;
+        };
+
+
+        /*************************************************************************
+        Spline fitting report:
+            TaskRCond       reciprocal of task's condition number
+            RMSError        RMS error
+            AvgError        average error
+            AvgRelError     average relative error (for non-zero Y[I])
+            MaxError        maximum error
+        *************************************************************************/
+        public struct spline1dfitreport
+        {
+            public double taskrcond;
+            public double rmserror;
+            public double avgerror;
+            public double avgrelerror;
+            public double maxerror;
+        };
+
+
+
+
+        public const int spline1dvnum = 11;
+
+
+        /*************************************************************************
+        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, N>=2
+            
+        OUTPUT PARAMETERS:
+            C   -   spline interpolant
+
+          -- ALGLIB PROJECT --
+             Copyright 24.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dbuildlinear(double[] x,
+            double[] y,
+            int n,
+            ref spline1dinterpolant c)
+        {
+            int i = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            System.Diagnostics.Debug.Assert(n>1, "Spline1DBuildLinear: N<2!");
+            
+            //
+            // Sort points
+            //
+            heapsortpoints(ref x, ref y, n);
+            
+            //
+            // Build
+            //
+            c.n = n;
+            c.k = 3;
+            c.x = new double[n];
+            c.c = new double[4*(n-1)];
+            for(i=0; i<=n-1; i++)
+            {
+                c.x[i] = x[i];
+            }
+            for(i=0; i<=n-2; i++)
+            {
+                c.c[4*i+0] = y[i];
+                c.c[4*i+1] = (y[i+1]-y[i])/(x[i+1]-x[i]);
+                c.c[4*i+2] = 0;
+                c.c[4*i+3] = 0;
+            }
+        }
+
+
+        /*************************************************************************
+        This subroutine builds cubic spline interpolant.
+
+        INPUT PARAMETERS:
+            X           -   spline nodes, array[0..N-1]
+            Y           -   function values, array[0..N-1]
+            N           -   points count, N>=2
+            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
+                            
+        The BoundLType/BoundRType parameters can have the following values:
+            * 0, which  corresponds  to  the  parabolically   terminated  spline
+                 (BoundL/BoundR are ignored).
+            * 1, which corresponds to the first derivative boundary condition
+            * 2, which corresponds to the second derivative boundary condition
+
+          -- ALGLIB PROJECT --
+             Copyright 23.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dbuildcubic(double[] x,
+            double[] y,
+            int n,
+            int boundltype,
+            double boundl,
+            int boundrtype,
+            double boundr,
+            ref spline1dinterpolant c)
+        {
+            double[] a1 = new double[0];
+            double[] a2 = new double[0];
+            double[] a3 = new double[0];
+            double[] b = new double[0];
+            double[] d = new double[0];
+            int i = 0;
+            int tblsize = 0;
+            double delta = 0;
+            double delta2 = 0;
+            double delta3 = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2, "BuildCubicSpline: N<2!");
+            System.Diagnostics.Debug.Assert(boundltype==0 | boundltype==1 | boundltype==2, "BuildCubicSpline: incorrect BoundLType!");
+            System.Diagnostics.Debug.Assert(boundrtype==0 | boundrtype==1 | boundrtype==2, "BuildCubicSpline: incorrect BoundRType!");
+            a1 = new double[n];
+            a2 = new double[n];
+            a3 = new double[n];
+            b = new double[n];
+            
+            //
+            // Special case:
+            // * N=2
+            // * parabolic terminated boundary condition on both ends
+            //
+            if( n==2 & boundltype==0 & boundrtype==0 )
+            {
+                
+                //
+                // Change task type
+                //
+                boundltype = 2;
+                boundl = 0;
+                boundrtype = 2;
+                boundr = 0;
+            }
+            
+            //
+            //
+            // Sort points
+            //
+            heapsortpoints(ref x, ref y, n);
+            
+            //
+            // Left boundary conditions
+            //
+            if( boundltype==0 )
+            {
+                a1[0] = 0;
+                a2[0] = 1;
+                a3[0] = 1;
+                b[0] = 2*(y[1]-y[0])/(x[1]-x[0]);
+            }
+            if( boundltype==1 )
+            {
+                a1[0] = 0;
+                a2[0] = 1;
+                a3[0] = 0;
+                b[0] = boundl;
+            }
+            if( boundltype==2 )
+            {
+                a1[0] = 0;
+                a2[0] = 2;
+                a3[0] = 1;
+                b[0] = 3*(y[1]-y[0])/(x[1]-x[0])-0.5*boundl*(x[1]-x[0]);
+            }
+            
+            //
+            // Central conditions
+            //
+            for(i=1; i<=n-2; i++)
+            {
+                a1[i] = x[i+1]-x[i];
+                a2[i] = 2*(x[i+1]-x[i-1]);
+                a3[i] = x[i]-x[i-1];
+                b[i] = 3*(y[i]-y[i-1])/(x[i]-x[i-1])*(x[i+1]-x[i])+3*(y[i+1]-y[i])/(x[i+1]-x[i])*(x[i]-x[i-1]);
+            }
+            
+            //
+            // Right boundary conditions
+            //
+            if( boundrtype==0 )
+            {
+                a1[n-1] = 1;
+                a2[n-1] = 1;
+                a3[n-1] = 0;
+                b[n-1] = 2*(y[n-1]-y[n-2])/(x[n-1]-x[n-2]);
+            }
+            if( boundrtype==1 )
+            {
+                a1[n-1] = 0;
+                a2[n-1] = 1;
+                a3[n-1] = 0;
+                b[n-1] = boundr;
+            }
+            if( boundrtype==2 )
+            {
+                a1[n-1] = 1;
+                a2[n-1] = 2;
+                a3[n-1] = 0;
+                b[n-1] = 3*(y[n-1]-y[n-2])/(x[n-1]-x[n-2])+0.5*boundr*(x[n-1]-x[n-2]);
+            }
+            
+            //
+            // Solve
+            //
+            solvetridiagonal(a1, a2, a3, b, n, ref d);
+            
+            //
+            // Now problem is reduced to the cubic Hermite spline
+            //
+            spline1dbuildhermite(x, y, d, n, ref c);
+        }
+
+
+        /*************************************************************************
+        This subroutine builds Hermite spline interpolant.
+
+        INPUT PARAMETERS:
+            X           -   spline nodes, array[0..N-1]
+            Y           -   function values, array[0..N-1]
+            D           -   derivatives, array[0..N-1]
+            N           -   points count, N>=2
+
+        OUTPUT PARAMETERS:
+            C           -   spline interpolant.
+
+          -- ALGLIB PROJECT --
+             Copyright 23.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dbuildhermite(double[] x,
+            double[] y,
+            double[] d,
+            int n,
+            ref spline1dinterpolant c)
+        {
+            int i = 0;
+            int tblsize = 0;
+            double delta = 0;
+            double delta2 = 0;
+            double delta3 = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            d = (double[])d.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2, "BuildHermiteSpline: N<2!");
+            
+            //
+            // Sort points
+            //
+            heapsortdpoints(ref x, ref y, ref d, n);
+            
+            //
+            // Build
+            //
+            c.x = new double[n];
+            c.c = new double[4*(n-1)];
+            c.k = 3;
+            c.n = n;
+            for(i=0; i<=n-1; i++)
+            {
+                c.x[i] = x[i];
+            }
+            for(i=0; i<=n-2; i++)
+            {
+                delta = x[i+1]-x[i];
+                delta2 = AP.Math.Sqr(delta);
+                delta3 = delta*delta2;
+                c.c[4*i+0] = y[i];
+                c.c[4*i+1] = d[i];
+                c.c[4*i+2] = (3*(y[i+1]-y[i])-2*d[i]*delta-d[i+1]*delta)/delta2;
+                c.c[4*i+3] = (2*(y[i]-y[i+1])+d[i]*delta+d[i+1]*delta)/delta3;
+            }
+        }
+
+
+        /*************************************************************************
+        This subroutine builds Akima spline interpolant
+
+        INPUT PARAMETERS:
+            X           -   spline nodes, array[0..N-1]
+            Y           -   function values, array[0..N-1]
+            N           -   points count, N>=5
+
+        OUTPUT PARAMETERS:
+            C           -   spline interpolant
+
+          -- ALGLIB PROJECT --
+             Copyright 24.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dbuildakima(double[] x,
+            double[] y,
+            int n,
+            ref spline1dinterpolant c)
+        {
+            int i = 0;
+            double[] d = new double[0];
+            double[] w = new double[0];
+            double[] diff = new double[0];
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=5, "BuildAkimaSpline: N<5!");
+            
+            //
+            // Sort points
+            //
+            heapsortpoints(ref x, ref y, n);
+            
+            //
+            // Prepare W (weights), Diff (divided differences)
+            //
+            w = new double[n-1];
+            diff = new double[n-1];
+            for(i=0; i<=n-2; i++)
+            {
+                diff[i] = (y[i+1]-y[i])/(x[i+1]-x[i]);
+            }
+            for(i=1; i<=n-2; i++)
+            {
+                w[i] = Math.Abs(diff[i]-diff[i-1]);
+            }
+            
+            //
+            // Prepare Hermite interpolation scheme
+            //
+            d = new double[n];
+            for(i=2; i<=n-3; i++)
+            {
+                if( (double)(Math.Abs(w[i-1])+Math.Abs(w[i+1]))!=(double)(0) )
+                {
+                    d[i] = (w[i+1]*diff[i-1]+w[i-1]*diff[i])/(w[i+1]+w[i-1]);
+                }
+                else
+                {
+                    d[i] = ((x[i+1]-x[i])*diff[i-1]+(x[i]-x[i-1])*diff[i])/(x[i+1]-x[i-1]);
+                }
+            }
+            d[0] = diffthreepoint(x[0], x[0], y[0], x[1], y[1], x[2], y[2]);
+            d[1] = diffthreepoint(x[1], x[0], y[0], x[1], y[1], x[2], y[2]);
+            d[n-2] = diffthreepoint(x[n-2], x[n-3], y[n-3], x[n-2], y[n-2], x[n-1], y[n-1]);
+            d[n-1] = diffthreepoint(x[n-1], x[n-3], y[n-3], x[n-2], y[n-2], x[n-1], y[n-1]);
+            
+            //
+            // Build Akima spline using Hermite interpolation scheme
+            //
+            spline1dbuildhermite(x, y, d, n, ref c);
+        }
+
+
+        /*************************************************************************
+        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, N>0.
+            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, 0<=K<M.
+                    K=0 means no constraints (XC/YC/DC are not used in such cases)
+            M   -   number of basis functions ( = number_of_nodes+2), M>=4.
+
+        OUTPUT PARAMETERS:
+            Info-   same format as in LSFitLinearWC() subroutine.
+                    * Info>0    task is solved
+                    * Info<=0   an error occured:
+                                -4 means inconvergence of internal SVD
+                                -3 means inconsistent constraints
+                                -1 means another errors in parameters passed
+                                   (N<=0, for example)
+            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.
+
+        SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
+
+        Setting constraints can lead  to undesired  results,  like ill-conditioned
+        behavior, or inconsistency being detected. From the other side,  it allows
+        us to improve quality of the fit. Here we summarize  our  experience  with
+        constrained regression splines:
+        * excessive constraints can be inconsistent. Splines are  piecewise  cubic
+          functions, and it is easy to create an example, where  large  number  of
+          constraints  concentrated  in  small  area will result in inconsistency.
+          Just because spline is not flexible enough to satisfy all of  them.  And
+          same constraints spread across the  [min(x),max(x)]  will  be  perfectly
+          consistent.
+        * the more evenly constraints are spread across [min(x),max(x)],  the more
+          chances that they will be consistent
+        * the  greater  is  M (given  fixed  constraints),  the  more chances that
+          constraints will be consistent
+        * in the general case, consistency of constraints IS NOT GUARANTEED.
+        * in the several special cases, however, we CAN guarantee consistency.
+        * one of this cases is constraints  on  the  function  values  AND/OR  its
+          derivatives at the interval boundaries.
+        * another  special  case  is ONE constraint on the function value (OR, but
+          not AND, derivative) anywhere in the interval
+
+        Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
+        can't solve your task without them. Anything beyond  special  cases  given
+        above is not guaranteed and may result in inconsistency.
+
+
+          -- ALGLIB PROJECT --
+             Copyright 18.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dfitcubicwc(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            int n,
+            ref double[] xc,
+            ref double[] yc,
+            ref int[] dc,
+            int k,
+            int m,
+            ref int info,
+            ref spline1dinterpolant s,
+            ref spline1dfitreport rep)
+        {
+            spline1dfitinternal(0, x, y, ref w, n, xc, yc, ref dc, k, m, ref info, ref s, ref rep);
+        }
+
+
+        /*************************************************************************
+        Weighted  fitting  by Hermite spline,  with constraints on function values
+        or first derivatives.
+
+        Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
+        basis functions. Basis functions are Hermite splines.  Small  regularizing
+        term is used when solving constrained tasks (to improve stability).
+
+        Task is linear, so linear least squares solver is used. Complexity of this
+        computational scheme is O(N*M^2), mostly dominated by least squares solver
+
+        SEE ALSO
+            Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
+                                        more smooth)
+            Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
+                                        invididual weights and constraints
+
+        INPUT PARAMETERS:
+            X   -   points, array[0..N-1].
+            Y   -   function values, array[0..N-1].
+            W   -   weights, array[0..N-1]
+                    Each summand in square  sum  of  approximation deviations from
+                    given  values  is  multiplied  by  the square of corresponding
+                    weight. Fill it by 1's if you don't  want  to  solve  weighted
+                    task.
+            N   -   number of points, N>0.
+            XC  -   points where 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, 0<=K<M.
+                    K=0 means no constraints (XC/YC/DC are not used in such cases)
+            M   -   number of basis functions (= 2 * number of nodes),
+                    M>=4,
+                    M IS EVEN!
+
+        OUTPUT PARAMETERS:
+            Info-   same format as in LSFitLinearW() subroutine:
+                    * Info>0    task is solved
+                    * Info<=0   an error occured:
+                                -4 means inconvergence of internal SVD
+                                -3 means inconsistent constraints
+                                -2 means odd M was passed (which is not supported)
+                                -1 means another errors in parameters passed
+                                   (N<=0, for example)
+            S   -   spline interpolant.
+            Rep -   report, same format as in LSFitLinearW() subroutine.
+                    Following fields are set:
+                    * RMSError      rms error on the (X,Y).
+                    * AvgError      average error on the (X,Y).
+                    * AvgRelError   average relative error on the non-zero Y
+                    * MaxError      maximum error
+                                    NON-WEIGHTED ERRORS ARE CALCULATED
+
+        IMPORTANT:
+            this subroitine doesn't calculate task's condition number for K<>0.
+
+        IMPORTANT:
+            this subroitine supports only even M's
+
+        SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
+
+        Setting constraints can lead  to undesired  results,  like ill-conditioned
+        behavior, or inconsistency being detected. From the other side,  it allows
+        us to improve quality of the fit. Here we summarize  our  experience  with
+        constrained regression splines:
+        * excessive constraints can be inconsistent. Splines are  piecewise  cubic
+          functions, and it is easy to create an example, where  large  number  of
+          constraints  concentrated  in  small  area will result in inconsistency.
+          Just because spline is not flexible enough to satisfy all of  them.  And
+          same constraints spread across the  [min(x),max(x)]  will  be  perfectly
+          consistent.
+        * the more evenly constraints are spread across [min(x),max(x)],  the more
+          chances that they will be consistent
+        * the  greater  is  M (given  fixed  constraints),  the  more chances that
+          constraints will be consistent
+        * in the general case, consistency of constraints is NOT GUARANTEED.
+        * in the several special cases, however, we can guarantee consistency.
+        * one of this cases is  M>=4  and   constraints  on   the  function  value
+          (AND/OR its derivative) at the interval boundaries.
+        * another special case is M>=4  and  ONE  constraint on the function value
+          (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
+
+        Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
+        can't solve your task without them. Anything beyond  special  cases  given
+        above is not guaranteed and may result in inconsistency.
+
+          -- ALGLIB PROJECT --
+             Copyright 18.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dfithermitewc(ref double[] x,
+            ref double[] y,
+            ref double[] w,
+            int n,
+            ref double[] xc,
+            ref double[] yc,
+            ref int[] dc,
+            int k,
+            int m,
+            ref int info,
+            ref spline1dinterpolant s,
+            ref spline1dfitreport rep)
+        {
+            spline1dfitinternal(1, x, y, ref w, n, xc, yc, ref dc, k, m, ref info, ref s, ref rep);
+        }
+
+
+        /*************************************************************************
+        Least squares fitting by cubic spline.
+
+        This subroutine is "lightweight" alternative for more complex and feature-
+        rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
+        about subroutine parameters (we don't duplicate it here because of length)
+
+          -- ALGLIB PROJECT --
+             Copyright 18.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dfitcubic(ref double[] x,
+            ref double[] y,
+            int n,
+            int m,
+            ref int info,
+            ref spline1dinterpolant s,
+            ref spline1dfitreport rep)
+        {
+            int i = 0;
+            double[] w = new double[0];
+            double[] xc = new double[0];
+            double[] yc = new double[0];
+            int[] dc = new int[0];
+
+            if( n>0 )
+            {
+                w = new double[n];
+                for(i=0; i<=n-1; i++)
+                {
+                    w[i] = 1;
+                }
+            }
+            spline1dfitcubicwc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref s, ref rep);
+        }
+
+
+        /*************************************************************************
+        Least squares fitting by Hermite spline.
+
+        This subroutine is "lightweight" alternative for more complex and feature-
+        rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
+        more information about subroutine parameters (we don't duplicate  it  here
+        because of length).
+
+          -- ALGLIB PROJECT --
+             Copyright 18.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dfithermite(ref double[] x,
+            ref double[] y,
+            int n,
+            int m,
+            ref int info,
+            ref spline1dinterpolant s,
+            ref spline1dfitreport rep)
+        {
+            int i = 0;
+            double[] w = new double[0];
+            double[] xc = new double[0];
+            double[] yc = new double[0];
+            int[] dc = new int[0];
+
+            if( n>0 )
+            {
+                w = new double[n];
+                for(i=0; i<=n-1; i++)
+                {
+                    w[i] = 1;
+                }
+            }
+            spline1dfithermitewc(ref x, ref y, ref w, n, ref xc, ref yc, ref dc, 0, m, ref info, ref s, ref rep);
+        }
+
+
+        /*************************************************************************
+        This subroutine calculates the value of the spline at the given point X.
+
+        INPUT PARAMETERS:
+            C   -   spline interpolant
+            X   -   point
+
+        Result:
+            S(x)
+
+          -- ALGLIB PROJECT --
+             Copyright 23.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double spline1dcalc(ref spline1dinterpolant c,
+            double x)
+        {
+            double result = 0;
+            int l = 0;
+            int r = 0;
+            int m = 0;
+
+            System.Diagnostics.Debug.Assert(c.k==3, "Spline1DCalc: internal error");
+            
+            //
+            // Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
+            //
+            l = 0;
+            r = c.n-2+1;
+            while( l!=r-1 )
+            {
+                m = (l+r)/2;
+                if( (double)(c.x[m])>=(double)(x) )
+                {
+                    r = m;
+                }
+                else
+                {
+                    l = m;
+                }
+            }
+            
+            //
+            // Interpolation
+            //
+            x = x-c.x[l];
+            m = 4*l;
+            result = c.c[m]+x*(c.c[m+1]+x*(c.c[m+2]+x*c.c[m+3]));
+            return result;
+        }
+
+
+        /*************************************************************************
+        This subroutine differentiates the spline.
+
+        INPUT PARAMETERS:
+            C   -   spline interpolant.
+            X   -   point
+
+        Result:
+            S   -   S(x)
+            DS  -   S'(x)
+            D2S -   S''(x)
+
+          -- ALGLIB PROJECT --
+             Copyright 24.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1ddiff(ref spline1dinterpolant c,
+            double x,
+            ref double s,
+            ref double ds,
+            ref double d2s)
+        {
+            int l = 0;
+            int r = 0;
+            int m = 0;
+
+            System.Diagnostics.Debug.Assert(c.k==3, "Spline1DCalc: internal error");
+            
+            //
+            // Binary search
+            //
+            l = 0;
+            r = c.n-2+1;
+            while( l!=r-1 )
+            {
+                m = (l+r)/2;
+                if( (double)(c.x[m])>=(double)(x) )
+                {
+                    r = m;
+                }
+                else
+                {
+                    l = m;
+                }
+            }
+            
+            //
+            // Differentiation
+            //
+            x = x-c.x[l];
+            m = 4*l;
+            s = c.c[m]+x*(c.c[m+1]+x*(c.c[m+2]+x*c.c[m+3]));
+            ds = c.c[m+1]+2*x*c.c[m+2]+3*AP.Math.Sqr(x)*c.c[m+3];
+            d2s = 2*c.c[m+2]+6*x*c.c[m+3];
+        }
+
+
+        /*************************************************************************
+        This subroutine makes the copy of the spline.
+
+        INPUT PARAMETERS:
+            C   -   spline interpolant.
+
+        Result:
+            CC  -   spline copy
+
+          -- ALGLIB PROJECT --
+             Copyright 29.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dcopy(ref spline1dinterpolant c,
+            ref spline1dinterpolant cc)
+        {
+            int i_ = 0;
+
+            cc.n = c.n;
+            cc.k = c.k;
+            cc.x = new double[cc.n];
+            for(i_=0; i_<=cc.n-1;i_++)
+            {
+                cc.x[i_] = c.x[i_];
+            }
+            cc.c = new double[(cc.k+1)*(cc.n-1)];
+            for(i_=0; i_<=(cc.k+1)*(cc.n-1)-1;i_++)
+            {
+                cc.c[i_] = c.c[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of the spline interpolant
+
+        INPUT PARAMETERS:
+            B   -   spline interpolant
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which contains interpolant,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dserialize(ref spline1dinterpolant c,
+            ref double[] ra,
+            ref int ralen)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            ralen = 2+2+c.n+(c.k+1)*(c.n-1);
+            ra = new double[ralen];
+            ra[0] = ralen;
+            ra[1] = spline1dvnum;
+            ra[2] = c.n;
+            ra[3] = c.k;
+            i1_ = (0) - (4);
+            for(i_=4; i_<=4+c.n-1;i_++)
+            {
+                ra[i_] = c.x[i_+i1_];
+            }
+            i1_ = (0) - (4+c.n);
+            for(i_=4+c.n; i_<=4+c.n+(c.k+1)*(c.n-1)-1;i_++)
+            {
+                ra[i_] = c.c[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Unserialization of the spline interpolant
+
+        INPUT PARAMETERS:
+            RA  -   array of real numbers which contains interpolant,
+
+        OUTPUT PARAMETERS:
+            B   -   spline interpolant
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dunserialize(ref double[] ra,
+            ref spline1dinterpolant c)
+        {
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[1])==spline1dvnum, "Spline1DUnserialize: corrupted array!");
+            c.n = (int)Math.Round(ra[2]);
+            c.k = (int)Math.Round(ra[3]);
+            c.x = new double[c.n];
+            c.c = new double[(c.k+1)*(c.n-1)];
+            i1_ = (4) - (0);
+            for(i_=0; i_<=c.n-1;i_++)
+            {
+                c.x[i_] = ra[i_+i1_];
+            }
+            i1_ = (4+c.n) - (0);
+            for(i_=0; i_<=(c.k+1)*(c.n-1)-1;i_++)
+            {
+                c.c[i_] = ra[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        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]
+
+          -- ALGLIB PROJECT --
+             Copyright 29.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dunpack(ref spline1dinterpolant c,
+            ref int n,
+            ref double[,] tbl)
+        {
+            int i = 0;
+            int j = 0;
+
+            tbl = new double[c.n-2+1, 2+c.k+1];
+            n = c.n;
+            
+            //
+            // Fill
+            //
+            for(i=0; i<=n-2; i++)
+            {
+                tbl[i,0] = c.x[i];
+                tbl[i,1] = c.x[i+1];
+                for(j=0; j<=c.k; j++)
+                {
+                    tbl[i,2+j] = c.c[(c.k+1)*i+j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        This subroutine performs linear transformation of the spline argument.
+
+        INPUT PARAMETERS:
+            C   -   spline interpolant.
+            A, B-   transformation coefficients: x = A*t + B
+        Result:
+            C   -   transformed spline
+
+          -- ALGLIB PROJECT --
+             Copyright 30.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dlintransx(ref spline1dinterpolant c,
+            double a,
+            double b)
+        {
+            int i = 0;
+            int j = 0;
+            int n = 0;
+            double v = 0;
+            double dv = 0;
+            double d2v = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[] d = new double[0];
+
+            n = c.n;
+            
+            //
+            // Special case: A=0
+            //
+            if( (double)(a)==(double)(0) )
+            {
+                v = spline1dcalc(ref c, b);
+                for(i=0; i<=n-2; i++)
+                {
+                    c.c[(c.k+1)*i] = v;
+                    for(j=1; j<=c.k; j++)
+                    {
+                        c.c[(c.k+1)*i+j] = 0;
+                    }
+                }
+                return;
+            }
+            
+            //
+            // General case: A<>0.
+            // Unpack, X, Y, dY/dX.
+            // Scale and pack again.
+            //
+            System.Diagnostics.Debug.Assert(c.k==3, "Spline1DLinTransX: internal error");
+            x = new double[n-1+1];
+            y = new double[n-1+1];
+            d = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                x[i] = c.x[i];
+                spline1ddiff(ref c, x[i], ref v, ref dv, ref d2v);
+                x[i] = (x[i]-b)/a;
+                y[i] = v;
+                d[i] = a*dv;
+            }
+            spline1dbuildhermite(x, y, d, n, ref 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
+
+          -- ALGLIB PROJECT --
+             Copyright 30.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline1dlintransy(ref spline1dinterpolant c,
+            double a,
+            double b)
+        {
+            int i = 0;
+            int j = 0;
+            int n = 0;
+
+            n = c.n;
+            for(i=0; i<=n-2; i++)
+            {
+                c.c[(c.k+1)*i] = a*c.c[(c.k+1)*i]+b;
+                for(j=1; j<=c.k; j++)
+                {
+                    c.c[(c.k+1)*i+j] = a*c.c[(c.k+1)*i+j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        This subroutine integrates the spline.
+
+        INPUT PARAMETERS:
+            C   -   spline interpolant.
+            X   -   right bound of the integration interval [a, x]
+        Result:
+            integral(S(t)dt,a,x)
+
+          -- ALGLIB PROJECT --
+             Copyright 23.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double spline1dintegrate(ref spline1dinterpolant c,
+            double x)
+        {
+            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;
+
+            n = c.n;
+            
+            //
+            // Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
+            //
+            l = 0;
+            r = n-2+1;
+            while( l!=r-1 )
+            {
+                m = (l+r)/2;
+                if( (double)(c.x[m])>=(double)(x) )
+                {
+                    r = m;
+                }
+                else
+                {
+                    l = m;
+                }
+            }
+            
+            //
+            // Integration
+            //
+            result = 0;
+            for(i=0; i<=l-1; i++)
+            {
+                w = c.x[i+1]-c.x[i];
+                m = (c.k+1)*i;
+                result = result+c.c[m]*w;
+                v = w;
+                for(j=1; j<=c.k; j++)
+                {
+                    v = v*w;
+                    result = result+c.c[m+j]*v/(j+1);
+                }
+            }
+            w = x-c.x[l];
+            m = (c.k+1)*l;
+            v = w;
+            result = result+c.c[m]*w;
+            for(j=1; j<=c.k; j++)
+            {
+                v = v*w;
+                result = result+c.c[m+j]*v/(j+1);
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal spline fitting subroutine
+
+          -- ALGLIB PROJECT --
+             Copyright 08.09.2009 by Bochkanov Sergey
+        *************************************************************************/
+        private static void spline1dfitinternal(int st,
+            double[] x,
+            double[] y,
+            ref double[] w,
+            int n,
+            double[] xc,
+            double[] yc,
+            ref int[] dc,
+            int k,
+            int m,
+            ref int info,
+            ref spline1dinterpolant s,
+            ref spline1dfitreport rep)
+        {
+            double[,] fmatrix = new double[0,0];
+            double[,] cmatrix = new double[0,0];
+            double[] y2 = new double[0];
+            double[] w2 = new double[0];
+            double[] sx = new double[0];
+            double[] sy = new double[0];
+            double[] sd = new double[0];
+            double[] tmp = new double[0];
+            double[] xoriginal = new double[0];
+            double[] yoriginal = new double[0];
+            lsfit.lsfitreport lrep = new lsfit.lsfitreport();
+            double v = 0;
+            double v0 = 0;
+            double v1 = 0;
+            double v2 = 0;
+            double mx = 0;
+            spline1dinterpolant s2 = new spline1dinterpolant();
+            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;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            xc = (double[])xc.Clone();
+            yc = (double[])yc.Clone();
+
+            System.Diagnostics.Debug.Assert(st==0 | st==1, "Spline1DFit: internal error!");
+            if( st==0 & m<4 )
+            {
+                info = -1;
+                return;
+            }
+            if( st==1 & m<4 )
+            {
+                info = -1;
+                return;
+            }
+            if( n<1 | k<0 | k>=m )
+            {
+                info = -1;
+                return;
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                info = 0;
+                if( dc[i]<0 )
+                {
+                    info = -1;
+                }
+                if( dc[i]>1 )
+                {
+                    info = -1;
+                }
+                if( info<0 )
+                {
+                    return;
+                }
+            }
+            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*AP.Math.MachineEpsilon;
+            
+            //
+            // Scale X, Y, XC, YC
+            //
+            lsfit.lsfitscalexy(ref x, ref y, n, ref xc, ref yc, ref dc, k, ref xa, ref xb, ref sa, ref sb, ref xoriginal, ref 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[]
+            //
+            y2 = new double[n+m];
+            w2 = new double[n+m];
+            fmatrix = new double[n+m, m];
+            if( k>0 )
+            {
+                cmatrix = new double[k, m+1];
+            }
+            if( st==0 )
+            {
+                
+                //
+                // allocate space for cubic spline
+                //
+                sx = new double[m-2];
+                sy = new double[m-2];
+                for(j=0; j<=m-2-1; j++)
+                {
+                    sx[j] = (double)(2*j)/((double)(m-2-1))-1;
+                }
+            }
+            if( st==1 )
+            {
+                
+                //
+                // allocate space for Hermite spline
+                //
+                sx = new double[m/2];
+                sy = new double[m/2];
+                sd = new double[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;
+                    if( j<m-2 )
+                    {
+                        sy[j] = 1;
+                    }
+                    if( j==m-2 )
+                    {
+                        bl = 1;
+                    }
+                    if( j==m-1 )
+                    {
+                        br = 1;
+                    }
+                    spline1dbuildcubic(sx, sy, m-2, 1, bl, 1, br, ref s2);
+                }
+                if( st==1 )
+                {
+                    
+                    //
+                    // Hermite basis
+                    //
+                    for(i=0; i<=m/2-1; i++)
+                    {
+                        sy[i] = 0;
+                        sd[i] = 0;
+                    }
+                    if( j%2==0 )
+                    {
+                        sy[j/2] = 1;
+                    }
+                    else
+                    {
+                        sd[j/2] = 1;
+                    }
+                    spline1dbuildhermite(sx, sy, sd, m/2, ref s2);
+                }
+                
+                //
+                // values at X[], XC[]
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    fmatrix[i,j] = spline1dcalc(ref s2, x[i]);
+                }
+                for(i=0; i<=k-1; i++)
+                {
+                    System.Diagnostics.Debug.Assert(dc[i]>=0 & dc[i]<=2, "Spline1DFit: internal error!");
+                    spline1ddiff(ref s2, xc[i], ref v0, ref v1, ref v2);
+                    if( dc[i]==0 )
+                    {
+                        cmatrix[i,j] = v0;
+                    }
+                    if( dc[i]==1 )
+                    {
+                        cmatrix[i,j] = v1;
+                    }
+                    if( dc[i]==2 )
+                    {
+                        cmatrix[i,j] = v2;
+                    }
+                }
+            }
+            for(i=0; i<=k-1; i++)
+            {
+                cmatrix[i,m] = yc[i];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=m-1; j++)
+                {
+                    if( i==j )
+                    {
+                        fmatrix[n+i,j] = decay;
+                    }
+                    else
+                    {
+                        fmatrix[n+i,j] = 0;
+                    }
+                }
+            }
+            y2 = new double[n+m];
+            w2 = new double[n+m];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                y2[i_] = y[i_];
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                w2[i_] = w[i_];
+            }
+            mx = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                mx = mx+Math.Abs(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
+                //
+                lsfit.lsfitlinearwc(y2, ref w2, ref fmatrix, cmatrix, n+m, m, k, ref info, ref tmp, ref lrep);
+            }
+            else
+            {
+                
+                //
+                // no constraints, no regularization needed
+                //
+                lsfit.lsfitlinearwc(y, ref w, ref fmatrix, cmatrix, n, m, k, ref info, ref tmp, ref lrep);
+            }
+            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_];
+                }
+                spline1dbuildcubic(sx, sy, m-2, 1, tmp[m-2], 1, tmp[m-1], ref s);
+            }
+            if( st==1 )
+            {
+                
+                //
+                // Hermite basis
+                //
+                for(i=0; i<=m/2-1; i++)
+                {
+                    sy[i] = tmp[2*i];
+                    sd[i] = tmp[2*i+1];
+                }
+                spline1dbuildhermite(sx, sy, sd, m/2, ref s);
+            }
+            spline1dlintransx(ref s, 2/(xb-xa), -((xa+xb)/(xb-xa)));
+            spline1dlintransy(ref s, sb-sa, sa);
+            
+            //
+            // Scale absolute errors obtained from LSFitLinearW.
+            // Relative error should be calculated separately
+            // (because of shifting/scaling of the task)
+            //
+            rep.taskrcond = lrep.taskrcond;
+            rep.rmserror = lrep.rmserror*(sb-sa);
+            rep.avgerror = lrep.avgerror*(sb-sa);
+            rep.maxerror = lrep.maxerror*(sb-sa);
+            rep.avgrelerror = 0;
+            relcnt = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(yoriginal[i])!=(double)(0) )
+                {
+                    rep.avgrelerror = rep.avgrelerror+Math.Abs(spline1dcalc(ref s, xoriginal[i])-yoriginal[i])/Math.Abs(yoriginal[i]);
+                    relcnt = relcnt+1;
+                }
+            }
+            if( relcnt!=0 )
+            {
+                rep.avgrelerror = rep.avgrelerror/relcnt;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Heap sort.
+        *************************************************************************/
+        private static void heapsortpoints(ref double[] x,
+            ref double[] y,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            bool isascending = new bool();
+            bool isdescending = new bool();
+
+            
+            //
+            // Test for already sorted set
+            //
+            isascending = true;
+            isdescending = true;
+            for(i=1; i<=n-1; i++)
+            {
+                isascending = isascending & (double)(x[i])>(double)(x[i-1]);
+                isdescending = isdescending & (double)(x[i])<(double)(x[i-1]);
+            }
+            if( isascending )
+            {
+                return;
+            }
+            if( isdescending )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    j = n-1-i;
+                    if( j<=i )
+                    {
+                        break;
+                    }
+                    tmp = x[i];
+                    x[i] = x[j];
+                    x[j] = tmp;
+                    tmp = y[i];
+                    y[i] = y[j];
+                    y[j] = tmp;
+                }
+                return;
+            }
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                return;
+            }
+            
+            //
+            // General case
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(x[k-1])>=(double)(x[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = x[k-1];
+                        x[k-1] = x[t-1];
+                        x[t-1] = tmp;
+                        tmp = y[k-1];
+                        y[k-1] = y[t-1];
+                        y[t-1] = tmp;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = x[i];
+                x[i] = x[0];
+                x[0] = tmp;
+                tmp = y[i];
+                y[i] = y[0];
+                y[0] = tmp;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(x[k])>(double)(x[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(x[t-1])>=(double)(x[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = x[k-1];
+                            x[k-1] = x[t-1];
+                            x[t-1] = tmp;
+                            tmp = y[k-1];
+                            y[k-1] = y[t-1];
+                            y[t-1] = tmp;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Heap sort.
+        *************************************************************************/
+        private static void heapsortdpoints(ref double[] x,
+            ref double[] y,
+            ref double[] d,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            bool isascending = new bool();
+            bool isdescending = new bool();
+
+            
+            //
+            // Test for already sorted set
+            //
+            isascending = true;
+            isdescending = true;
+            for(i=1; i<=n-1; i++)
+            {
+                isascending = isascending & (double)(x[i])>(double)(x[i-1]);
+                isdescending = isdescending & (double)(x[i])<(double)(x[i-1]);
+            }
+            if( isascending )
+            {
+                return;
+            }
+            if( isdescending )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    j = n-1-i;
+                    if( j<=i )
+                    {
+                        break;
+                    }
+                    tmp = x[i];
+                    x[i] = x[j];
+                    x[j] = tmp;
+                    tmp = y[i];
+                    y[i] = y[j];
+                    y[j] = tmp;
+                    tmp = d[i];
+                    d[i] = d[j];
+                    d[j] = tmp;
+                }
+                return;
+            }
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                return;
+            }
+            
+            //
+            // General case
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(x[k-1])>=(double)(x[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = x[k-1];
+                        x[k-1] = x[t-1];
+                        x[t-1] = tmp;
+                        tmp = y[k-1];
+                        y[k-1] = y[t-1];
+                        y[t-1] = tmp;
+                        tmp = d[k-1];
+                        d[k-1] = d[t-1];
+                        d[t-1] = tmp;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = x[i];
+                x[i] = x[0];
+                x[0] = tmp;
+                tmp = y[i];
+                y[i] = y[0];
+                y[0] = tmp;
+                tmp = d[i];
+                d[i] = d[0];
+                d[0] = tmp;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(x[k])>(double)(x[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(x[t-1])>=(double)(x[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = x[k-1];
+                            x[k-1] = x[t-1];
+                            x[t-1] = tmp;
+                            tmp = y[k-1];
+                            y[k-1] = y[t-1];
+                            y[t-1] = tmp;
+                            tmp = d[k-1];
+                            d[k-1] = d[t-1];
+                            d[t-1] = tmp;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Tridiagonal solver.
+        *************************************************************************/
+        private static void solvetridiagonal(double[] a,
+            double[] b,
+            double[] c,
+            double[] d,
+            int n,
+            ref double[] x)
+        {
+            int k = 0;
+            double t = 0;
+
+            a = (double[])a.Clone();
+            b = (double[])b.Clone();
+            c = (double[])c.Clone();
+            d = (double[])d.Clone();
+
+            x = new double[n-1+1];
+            a[0] = 0;
+            c[n-1] = 0;
+            for(k=1; k<=n-1; k++)
+            {
+                t = a[k]/b[k-1];
+                b[k] = b[k]-t*c[k-1];
+                d[k] = d[k]-t*d[k-1];
+            }
+            x[n-1] = d[n-1]/b[n-1];
+            for(k=n-2; k>=0; k--)
+            {
+                x[k] = (d[k]-c[k]*x[k+1])/b[k];
+            }
+        }
+
+
+        /*************************************************************************
+        Internal subroutine. Three-point differentiation
+        *************************************************************************/
+        private static double diffthreepoint(double t,
+            double x0,
+            double f0,
+            double x1,
+            double f1,
+            double x2,
+            double f2)
+        {
+            double result = 0;
+            double a = 0;
+            double b = 0;
+
+            t = t-x0;
+            x1 = x1-x0;
+            x2 = x2-x0;
+            a = (f2-f0-x2/x1*(f1-f0))/(AP.Math.Sqr(x2)-x1*x2);
+            b = (f1-f0-a*AP.Math.Sqr(x1))/x1;
+            result = 2*a*t+b;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline2d.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline2d.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline2d.cs	(revision 2645)
@@ -0,0 +1,1246 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spline2d
+    {
+        /*************************************************************************
+        2-dimensional spline inteprolant
+        *************************************************************************/
+        public struct spline2dinterpolant
+        {
+            public int k;
+            public double[] c;
+        };
+
+
+
+
+        public const int spline2dvnum = 12;
+
+
+        /*************************************************************************
+        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
+
+          -- ALGLIB PROJECT --
+             Copyright 05.07.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dbuildbilinear(double[] x,
+            double[] y,
+            double[,] f,
+            int m,
+            int n,
+            ref spline2dinterpolant c)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int tblsize = 0;
+            int shift = 0;
+            double t = 0;
+            double[,] dx = new double[0,0];
+            double[,] dy = new double[0,0];
+            double[,] dxy = new double[0,0];
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            f = (double[,])f.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2 & m>=2, "Spline2DBuildBilinear: N<2 or M<2!");
+            
+            //
+            // Sort points
+            //
+            for(j=0; j<=n-1; j++)
+            {
+                k = j;
+                for(i=j+1; i<=n-1; i++)
+                {
+                    if( (double)(x[i])<(double)(x[k]) )
+                    {
+                        k = i;
+                    }
+                }
+                if( k!=j )
+                {
+                    for(i=0; i<=m-1; i++)
+                    {
+                        t = f[i,j];
+                        f[i,j] = f[i,k];
+                        f[i,k] = t;
+                    }
+                    t = x[j];
+                    x[j] = x[k];
+                    x[k] = t;
+                }
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                k = i;
+                for(j=i+1; j<=m-1; j++)
+                {
+                    if( (double)(y[j])<(double)(y[k]) )
+                    {
+                        k = j;
+                    }
+                }
+                if( k!=i )
+                {
+                    for(j=0; j<=n-1; j++)
+                    {
+                        t = f[i,j];
+                        f[i,j] = f[k,j];
+                        f[k,j] = t;
+                    }
+                    t = y[i];
+                    y[i] = y[k];
+                    y[k] = t;
+                }
+            }
+            
+            //
+            // Fill C:
+            //  C[0]            -   length(C)
+            //  C[1]            -   type(C):
+            //                      -1 = bilinear interpolant
+            //                      -3 = general cubic spline
+            //                           (see BuildBicubicSpline)
+            //  C[2]:
+            //      N (x count)
+            //  C[3]:
+            //      M (y count)
+            //  C[4]...C[4+N-1]:
+            //      x[i], i = 0...N-1
+            //  C[4+N]...C[4+N+M-1]:
+            //      y[i], i = 0...M-1
+            //  C[4+N+M]...C[4+N+M+(N*M-1)]:
+            //      f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on...
+            //
+            c.k = 1;
+            tblsize = 4+n+m+n*m;
+            c.c = new double[tblsize-1+1];
+            c.c[0] = tblsize;
+            c.c[1] = -1;
+            c.c[2] = n;
+            c.c[3] = m;
+            for(i=0; i<=n-1; i++)
+            {
+                c.c[4+i] = x[i];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                c.c[4+n+i] = y[i];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    shift = i*n+j;
+                    c.c[4+n+m+shift] = f[i,j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        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
+
+          -- ALGLIB PROJECT --
+             Copyright 05.07.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dbuildbicubic(double[] x,
+            double[] y,
+            double[,] f,
+            int m,
+            int n,
+            ref spline2dinterpolant c)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int tblsize = 0;
+            int shift = 0;
+            double t = 0;
+            double[,] dx = new double[0,0];
+            double[,] dy = new double[0,0];
+            double[,] dxy = new double[0,0];
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            f = (double[,])f.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2 & m>=2, "BuildBicubicSpline: N<2 or M<2!");
+            
+            //
+            // Sort points
+            //
+            for(j=0; j<=n-1; j++)
+            {
+                k = j;
+                for(i=j+1; i<=n-1; i++)
+                {
+                    if( (double)(x[i])<(double)(x[k]) )
+                    {
+                        k = i;
+                    }
+                }
+                if( k!=j )
+                {
+                    for(i=0; i<=m-1; i++)
+                    {
+                        t = f[i,j];
+                        f[i,j] = f[i,k];
+                        f[i,k] = t;
+                    }
+                    t = x[j];
+                    x[j] = x[k];
+                    x[k] = t;
+                }
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                k = i;
+                for(j=i+1; j<=m-1; j++)
+                {
+                    if( (double)(y[j])<(double)(y[k]) )
+                    {
+                        k = j;
+                    }
+                }
+                if( k!=i )
+                {
+                    for(j=0; j<=n-1; j++)
+                    {
+                        t = f[i,j];
+                        f[i,j] = f[k,j];
+                        f[k,j] = t;
+                    }
+                    t = y[i];
+                    y[i] = y[k];
+                    y[k] = t;
+                }
+            }
+            
+            //
+            // Fill C:
+            //  C[0]            -   length(C)
+            //  C[1]            -   type(C):
+            //                      -1 = bilinear interpolant
+            //                           (see BuildBilinearInterpolant)
+            //                      -3 = general cubic spline
+            //  C[2]:
+            //      N (x count)
+            //  C[3]:
+            //      M (y count)
+            //  C[4]...C[4+N-1]:
+            //      x[i], i = 0...N-1
+            //  C[4+N]...C[4+N+M-1]:
+            //      y[i], i = 0...M-1
+            //  C[4+N+M]...C[4+N+M+(N*M-1)]:
+            //      f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on...
+            //  C[4+N+M+N*M]...C[4+N+M+(2*N*M-1)]:
+            //      df(i,j)/dx table.
+            //  C[4+N+M+2*N*M]...C[4+N+M+(3*N*M-1)]:
+            //      df(i,j)/dy table.
+            //  C[4+N+M+3*N*M]...C[4+N+M+(4*N*M-1)]:
+            //      d2f(i,j)/dxdy table.
+            //
+            c.k = 3;
+            tblsize = 4+n+m+4*n*m;
+            c.c = new double[tblsize-1+1];
+            c.c[0] = tblsize;
+            c.c[1] = -3;
+            c.c[2] = n;
+            c.c[3] = m;
+            for(i=0; i<=n-1; i++)
+            {
+                c.c[4+i] = x[i];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                c.c[4+n+i] = y[i];
+            }
+            bicubiccalcderivatives(ref f, ref x, ref y, m, n, ref dx, ref dy, ref dxy);
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    shift = i*n+j;
+                    c.c[4+n+m+shift] = f[i,j];
+                    c.c[4+n+m+n*m+shift] = dx[i,j];
+                    c.c[4+n+m+2*n*m+shift] = dy[i,j];
+                    c.c[4+n+m+3*n*m+shift] = dxy[i,j];
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        This subroutine calculates the value of the bilinear or bicubic spline  at
+        the given point X.
+
+        Input parameters:
+            C   -   coefficients table.
+                    Built by BuildBilinearSpline or BuildBicubicSpline.
+            X, Y-   point
+
+        Result:
+            S(x,y)
+
+          -- ALGLIB PROJECT --
+             Copyright 05.07.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static double spline2dcalc(ref spline2dinterpolant c,
+            double x,
+            double y)
+        {
+            double result = 0;
+            double v = 0;
+            double vx = 0;
+            double vy = 0;
+            double vxy = 0;
+
+            spline2ddiff(ref c, x, y, ref v, ref vx, ref vy, ref vxy);
+            result = v;
+            return result;
+        }
+
+
+        /*************************************************************************
+        This subroutine calculates the value of the bilinear or bicubic spline  at
+        the given point X and its derivatives.
+
+        Input parameters:
+            C   -   spline interpolant.
+            X, Y-   point
+
+        Output parameters:
+            F   -   S(x,y)
+            FX  -   dS(x,y)/dX
+            FY  -   dS(x,y)/dY
+            FXY -   d2S(x,y)/dXdY
+
+          -- ALGLIB PROJECT --
+             Copyright 05.07.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2ddiff(ref spline2dinterpolant c,
+            double x,
+            double y,
+            ref double f,
+            ref double fx,
+            ref double fy,
+            ref double fxy)
+        {
+            int n = 0;
+            int m = 0;
+            double t = 0;
+            double dt = 0;
+            double u = 0;
+            double du = 0;
+            int i = 0;
+            int j = 0;
+            int ix = 0;
+            int iy = 0;
+            int l = 0;
+            int r = 0;
+            int h = 0;
+            int shift1 = 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 v = 0;
+            double t0 = 0;
+            double t1 = 0;
+            double t2 = 0;
+            double t3 = 0;
+            double u0 = 0;
+            double u1 = 0;
+            double u2 = 0;
+            double u3 = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c.c[1])==-1 | (int)Math.Round(c.c[1])==-3, "Spline2DDiff: incorrect C!");
+            n = (int)Math.Round(c.c[2]);
+            m = (int)Math.Round(c.c[3]);
+            
+            //
+            // Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
+            //
+            l = 4;
+            r = 4+n-2+1;
+            while( l!=r-1 )
+            {
+                h = (l+r)/2;
+                if( (double)(c.c[h])>=(double)(x) )
+                {
+                    r = h;
+                }
+                else
+                {
+                    l = h;
+                }
+            }
+            t = (x-c.c[l])/(c.c[l+1]-c.c[l]);
+            dt = 1.0/(c.c[l+1]-c.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;
+                if( (double)(c.c[h])>=(double)(y) )
+                {
+                    r = h;
+                }
+                else
+                {
+                    l = h;
+                }
+            }
+            u = (y-c.c[l])/(c.c[l+1]-c.c[l]);
+            du = 1.0/(c.c[l+1]-c.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)Math.Round(c.c[1])==-1 )
+            {
+                shift1 = 4+n+m;
+                y1 = c.c[shift1+n*iy+ix];
+                y2 = c.c[shift1+n*iy+(ix+1)];
+                y3 = c.c[shift1+n*(iy+1)+(ix+1)];
+                y4 = c.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;
+                return;
+            }
+            
+            //
+            // Bicubic interpolation
+            //
+            if( (int)Math.Round(c.c[1])==-3 )
+            {
+                
+                //
+                // Prepare info
+                //
+                t0 = 1;
+                t1 = t;
+                t2 = AP.Math.Sqr(t);
+                t3 = t*t2;
+                u0 = 1;
+                u1 = u;
+                u2 = AP.Math.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.c[sf+s1]);
+                f = f+v*t0*u0;
+                v = +(1*c.c[sfy+s1]/du);
+                f = f+v*t0*u1;
+                fy = fy+1*v*t0*u0*du;
+                v = -(3*c.c[sf+s1])+3*c.c[sf+s4]-2*c.c[sfy+s1]/du-1*c.c[sfy+s4]/du;
+                f = f+v*t0*u2;
+                fy = fy+2*v*t0*u1*du;
+                v = +(2*c.c[sf+s1])-2*c.c[sf+s4]+1*c.c[sfy+s1]/du+1*c.c[sfy+s4]/du;
+                f = f+v*t0*u3;
+                fy = fy+3*v*t0*u2*du;
+                v = +(1*c.c[sfx+s1]/dt);
+                f = f+v*t1*u0;
+                fx = fx+1*v*t0*u0*dt;
+                v = +(1*c.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.c[sfx+s1]/dt)+3*c.c[sfx+s4]/dt-2*c.c[sfxy+s1]/(dt*du)-1*c.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.c[sfx+s1]/dt)-2*c.c[sfx+s4]/dt+1*c.c[sfxy+s1]/(dt*du)+1*c.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.c[sf+s1])+3*c.c[sf+s2]-2*c.c[sfx+s1]/dt-1*c.c[sfx+s2]/dt;
+                f = f+v*t2*u0;
+                fx = fx+2*v*t1*u0*dt;
+                v = -(3*c.c[sfy+s1]/du)+3*c.c[sfy+s2]/du-2*c.c[sfxy+s1]/(dt*du)-1*c.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.c[sf+s1])-9*c.c[sf+s2]+9*c.c[sf+s3]-9*c.c[sf+s4]+6*c.c[sfx+s1]/dt+3*c.c[sfx+s2]/dt-3*c.c[sfx+s3]/dt-6*c.c[sfx+s4]/dt+6*c.c[sfy+s1]/du-6*c.c[sfy+s2]/du-3*c.c[sfy+s3]/du+3*c.c[sfy+s4]/du+4*c.c[sfxy+s1]/(dt*du)+2*c.c[sfxy+s2]/(dt*du)+1*c.c[sfxy+s3]/(dt*du)+2*c.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.c[sf+s1])+6*c.c[sf+s2]-6*c.c[sf+s3]+6*c.c[sf+s4]-4*c.c[sfx+s1]/dt-2*c.c[sfx+s2]/dt+2*c.c[sfx+s3]/dt+4*c.c[sfx+s4]/dt-3*c.c[sfy+s1]/du+3*c.c[sfy+s2]/du+3*c.c[sfy+s3]/du-3*c.c[sfy+s4]/du-2*c.c[sfxy+s1]/(dt*du)-1*c.c[sfxy+s2]/(dt*du)-1*c.c[sfxy+s3]/(dt*du)-2*c.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.c[sf+s1])-2*c.c[sf+s2]+1*c.c[sfx+s1]/dt+1*c.c[sfx+s2]/dt;
+                f = f+v*t3*u0;
+                fx = fx+3*v*t2*u0*dt;
+                v = +(2*c.c[sfy+s1]/du)-2*c.c[sfy+s2]/du+1*c.c[sfxy+s1]/(dt*du)+1*c.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.c[sf+s1])+6*c.c[sf+s2]-6*c.c[sf+s3]+6*c.c[sf+s4]-3*c.c[sfx+s1]/dt-3*c.c[sfx+s2]/dt+3*c.c[sfx+s3]/dt+3*c.c[sfx+s4]/dt-4*c.c[sfy+s1]/du+4*c.c[sfy+s2]/du+2*c.c[sfy+s3]/du-2*c.c[sfy+s4]/du-2*c.c[sfxy+s1]/(dt*du)-2*c.c[sfxy+s2]/(dt*du)-1*c.c[sfxy+s3]/(dt*du)-1*c.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.c[sf+s1])-4*c.c[sf+s2]+4*c.c[sf+s3]-4*c.c[sf+s4]+2*c.c[sfx+s1]/dt+2*c.c[sfx+s2]/dt-2*c.c[sfx+s3]/dt-2*c.c[sfx+s4]/dt+2*c.c[sfy+s1]/du-2*c.c[sfy+s2]/du-2*c.c[sfy+s3]/du+2*c.c[sfy+s4]/du+1*c.c[sfxy+s1]/(dt*du)+1*c.c[sfxy+s2]/(dt*du)+1*c.c[sfxy+s3]/(dt*du)+1*c.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;
+                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]
+
+          -- ALGLIB PROJECT --
+             Copyright 29.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dunpack(ref spline2dinterpolant c,
+            ref int m,
+            ref int n,
+            ref double[,] tbl)
+        {
+            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;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c.c[1])==-3 | (int)Math.Round(c.c[1])==-1, "SplineUnpack2D: incorrect C!");
+            n = (int)Math.Round(c.c[2]);
+            m = (int)Math.Round(c.c[3]);
+            tbl = new double[(n-1)*(m-1)-1+1, 19+1];
+            
+            //
+            // Fill
+            //
+            for(i=0; i<=m-2; i++)
+            {
+                for(j=0; j<=n-2; j++)
+                {
+                    p = i*(n-1)+j;
+                    tbl[p,0] = c.c[4+j];
+                    tbl[p,1] = c.c[4+j+1];
+                    tbl[p,2] = c.c[4+n+i];
+                    tbl[p,3] = c.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)Math.Round(c.c[1])==-1 )
+                    {
+                        for(k=4; k<=19; k++)
+                        {
+                            tbl[p,k] = 0;
+                        }
+                        shift = 4+n+m;
+                        y1 = c.c[shift+n*i+j];
+                        y2 = c.c[shift+n*i+(j+1)];
+                        y3 = c.c[shift+n*(i+1)+(j+1)];
+                        y4 = c.c[shift+n*(i+1)+j];
+                        tbl[p,4] = y1;
+                        tbl[p,4+1*4+0] = y2-y1;
+                        tbl[p,4+0*4+1] = y4-y1;
+                        tbl[p,4+1*4+1] = y3-y2-y4+y1;
+                    }
+                    
+                    //
+                    // Bicubic interpolation
+                    //
+                    if( (int)Math.Round(c.c[1])==-3 )
+                    {
+                        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;
+                        tbl[p,4+0*4+0] = +(1*c.c[sf+s1]);
+                        tbl[p,4+0*4+1] = +(1*c.c[sfy+s1]/du);
+                        tbl[p,4+0*4+2] = -(3*c.c[sf+s1])+3*c.c[sf+s4]-2*c.c[sfy+s1]/du-1*c.c[sfy+s4]/du;
+                        tbl[p,4+0*4+3] = +(2*c.c[sf+s1])-2*c.c[sf+s4]+1*c.c[sfy+s1]/du+1*c.c[sfy+s4]/du;
+                        tbl[p,4+1*4+0] = +(1*c.c[sfx+s1]/dt);
+                        tbl[p,4+1*4+1] = +(1*c.c[sfxy+s1]/(dt*du));
+                        tbl[p,4+1*4+2] = -(3*c.c[sfx+s1]/dt)+3*c.c[sfx+s4]/dt-2*c.c[sfxy+s1]/(dt*du)-1*c.c[sfxy+s4]/(dt*du);
+                        tbl[p,4+1*4+3] = +(2*c.c[sfx+s1]/dt)-2*c.c[sfx+s4]/dt+1*c.c[sfxy+s1]/(dt*du)+1*c.c[sfxy+s4]/(dt*du);
+                        tbl[p,4+2*4+0] = -(3*c.c[sf+s1])+3*c.c[sf+s2]-2*c.c[sfx+s1]/dt-1*c.c[sfx+s2]/dt;
+                        tbl[p,4+2*4+1] = -(3*c.c[sfy+s1]/du)+3*c.c[sfy+s2]/du-2*c.c[sfxy+s1]/(dt*du)-1*c.c[sfxy+s2]/(dt*du);
+                        tbl[p,4+2*4+2] = +(9*c.c[sf+s1])-9*c.c[sf+s2]+9*c.c[sf+s3]-9*c.c[sf+s4]+6*c.c[sfx+s1]/dt+3*c.c[sfx+s2]/dt-3*c.c[sfx+s3]/dt-6*c.c[sfx+s4]/dt+6*c.c[sfy+s1]/du-6*c.c[sfy+s2]/du-3*c.c[sfy+s3]/du+3*c.c[sfy+s4]/du+4*c.c[sfxy+s1]/(dt*du)+2*c.c[sfxy+s2]/(dt*du)+1*c.c[sfxy+s3]/(dt*du)+2*c.c[sfxy+s4]/(dt*du);
+                        tbl[p,4+2*4+3] = -(6*c.c[sf+s1])+6*c.c[sf+s2]-6*c.c[sf+s3]+6*c.c[sf+s4]-4*c.c[sfx+s1]/dt-2*c.c[sfx+s2]/dt+2*c.c[sfx+s3]/dt+4*c.c[sfx+s4]/dt-3*c.c[sfy+s1]/du+3*c.c[sfy+s2]/du+3*c.c[sfy+s3]/du-3*c.c[sfy+s4]/du-2*c.c[sfxy+s1]/(dt*du)-1*c.c[sfxy+s2]/(dt*du)-1*c.c[sfxy+s3]/(dt*du)-2*c.c[sfxy+s4]/(dt*du);
+                        tbl[p,4+3*4+0] = +(2*c.c[sf+s1])-2*c.c[sf+s2]+1*c.c[sfx+s1]/dt+1*c.c[sfx+s2]/dt;
+                        tbl[p,4+3*4+1] = +(2*c.c[sfy+s1]/du)-2*c.c[sfy+s2]/du+1*c.c[sfxy+s1]/(dt*du)+1*c.c[sfxy+s2]/(dt*du);
+                        tbl[p,4+3*4+2] = -(6*c.c[sf+s1])+6*c.c[sf+s2]-6*c.c[sf+s3]+6*c.c[sf+s4]-3*c.c[sfx+s1]/dt-3*c.c[sfx+s2]/dt+3*c.c[sfx+s3]/dt+3*c.c[sfx+s4]/dt-4*c.c[sfy+s1]/du+4*c.c[sfy+s2]/du+2*c.c[sfy+s3]/du-2*c.c[sfy+s4]/du-2*c.c[sfxy+s1]/(dt*du)-2*c.c[sfxy+s2]/(dt*du)-1*c.c[sfxy+s3]/(dt*du)-1*c.c[sfxy+s4]/(dt*du);
+                        tbl[p,4+3*4+3] = +(4*c.c[sf+s1])-4*c.c[sf+s2]+4*c.c[sf+s3]-4*c.c[sf+s4]+2*c.c[sfx+s1]/dt+2*c.c[sfx+s2]/dt-2*c.c[sfx+s3]/dt-2*c.c[sfx+s4]/dt+2*c.c[sfy+s1]/du-2*c.c[sfy+s2]/du-2*c.c[sfy+s3]/du+2*c.c[sfy+s4]/du+1*c.c[sfxy+s1]/(dt*du)+1*c.c[sfxy+s2]/(dt*du)+1*c.c[sfxy+s3]/(dt*du)+1*c.c[sfxy+s4]/(dt*du);
+                    }
+                    
+                    //
+                    // Rescale Cij
+                    //
+                    for(ci=0; ci<=3; ci++)
+                    {
+                        for(cj=0; cj<=3; cj++)
+                        {
+                            tbl[p,4+ci*4+cj] = tbl[p,4+ci*4+cj]*Math.Pow(dt, ci)*Math.Pow(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
+
+          -- ALGLIB PROJECT --
+             Copyright 30.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dlintransxy(ref spline2dinterpolant c,
+            double ax,
+            double bx,
+            double ay,
+            double by)
+        {
+            int i = 0;
+            int j = 0;
+            int n = 0;
+            int m = 0;
+            double v = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[,] f = new double[0,0];
+            int typec = 0;
+
+            typec = (int)Math.Round(c.c[1]);
+            System.Diagnostics.Debug.Assert(typec==-3 | typec==-1, "Spline2DLinTransXY: incorrect C!");
+            n = (int)Math.Round(c.c[2]);
+            m = (int)Math.Round(c.c[3]);
+            x = new double[n-1+1];
+            y = new double[m-1+1];
+            f = new double[m-1+1, n-1+1];
+            for(j=0; j<=n-1; j++)
+            {
+                x[j] = c.c[4+j];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                y[i] = c.c[4+n+i];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    f[i,j] = c.c[4+n+m+i*n+j];
+                }
+            }
+            
+            //
+            // Special case: AX=0 or AY=0
+            //
+            if( (double)(ax)==(double)(0) )
+            {
+                for(i=0; i<=m-1; i++)
+                {
+                    v = spline2dcalc(ref c, bx, y[i]);
+                    for(j=0; j<=n-1; j++)
+                    {
+                        f[i,j] = v;
+                    }
+                }
+                if( typec==-3 )
+                {
+                    spline2dbuildbicubic(x, y, f, m, n, ref c);
+                }
+                if( typec==-1 )
+                {
+                    spline2dbuildbilinear(x, y, f, m, n, ref c);
+                }
+                ax = 1;
+                bx = 0;
+            }
+            if( (double)(ay)==(double)(0) )
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    v = spline2dcalc(ref c, x[j], by);
+                    for(i=0; i<=m-1; i++)
+                    {
+                        f[i,j] = v;
+                    }
+                }
+                if( typec==-3 )
+                {
+                    spline2dbuildbicubic(x, y, f, m, n, ref c);
+                }
+                if( typec==-1 )
+                {
+                    spline2dbuildbilinear(x, y, f, m, n, ref c);
+                }
+                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;
+            }
+            if( typec==-3 )
+            {
+                spline2dbuildbicubic(x, y, f, m, n, ref c);
+            }
+            if( typec==-1 )
+            {
+                spline2dbuildbilinear(x, y, f, m, n, ref 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
+
+          -- ALGLIB PROJECT --
+             Copyright 30.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dlintransf(ref spline2dinterpolant c,
+            double a,
+            double b)
+        {
+            int i = 0;
+            int j = 0;
+            int n = 0;
+            int m = 0;
+            double v = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[,] f = new double[0,0];
+            int typec = 0;
+
+            typec = (int)Math.Round(c.c[1]);
+            System.Diagnostics.Debug.Assert(typec==-3 | typec==-1, "Spline2DLinTransXY: incorrect C!");
+            n = (int)Math.Round(c.c[2]);
+            m = (int)Math.Round(c.c[3]);
+            x = new double[n-1+1];
+            y = new double[m-1+1];
+            f = new double[m-1+1, n-1+1];
+            for(j=0; j<=n-1; j++)
+            {
+                x[j] = c.c[4+j];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                y[i] = c.c[4+n+i];
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    f[i,j] = a*c.c[4+n+m+i*n+j]+b;
+                }
+            }
+            if( typec==-3 )
+            {
+                spline2dbuildbicubic(x, y, f, m, n, ref c);
+            }
+            if( typec==-1 )
+            {
+                spline2dbuildbilinear(x, y, f, m, n, ref c);
+            }
+        }
+
+
+        /*************************************************************************
+        This subroutine makes the copy of the spline model.
+
+        Input parameters:
+            C   -   spline interpolant
+
+        Output parameters:
+            CC  -   spline copy
+
+          -- ALGLIB PROJECT --
+             Copyright 29.06.2007 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dcopy(ref spline2dinterpolant c,
+            ref spline2dinterpolant cc)
+        {
+            int n = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(c.k==1 | c.k==3, "Spline2DCopy: incorrect C!");
+            cc.k = c.k;
+            n = (int)Math.Round(c.c[0]);
+            cc.c = new double[n];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                cc.c[i_] = c.c[i_];
+            }
+        }
+
+
+        /*************************************************************************
+        Serialization of the spline interpolant
+
+        INPUT PARAMETERS:
+            B   -   spline interpolant
+
+        OUTPUT PARAMETERS:
+            RA      -   array of real numbers which contains interpolant,
+                        array[0..RLen-1]
+            RLen    -   RA lenght
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dserialize(ref spline2dinterpolant c,
+            ref double[] ra,
+            ref int ralen)
+        {
+            int clen = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(c.k==1 | c.k==3, "Spline2DSerialize: incorrect C!");
+            clen = (int)Math.Round(c.c[0]);
+            ralen = 3+clen;
+            ra = new double[ralen];
+            ra[0] = ralen;
+            ra[1] = spline2dvnum;
+            ra[2] = c.k;
+            i1_ = (0) - (3);
+            for(i_=3; i_<=3+clen-1;i_++)
+            {
+                ra[i_] = c.c[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Unserialization of the spline interpolant
+
+        INPUT PARAMETERS:
+            RA  -   array of real numbers which contains interpolant,
+
+        OUTPUT PARAMETERS:
+            B   -   spline interpolant
+
+          -- ALGLIB --
+             Copyright 17.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dunserialize(ref double[] ra,
+            ref spline2dinterpolant c)
+        {
+            int clen = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(ra[1])==spline2dvnum, "Spline2DUnserialize: corrupted array!");
+            c.k = (int)Math.Round(ra[2]);
+            clen = (int)Math.Round(ra[3]);
+            c.c = new double[clen];
+            i1_ = (3) - (0);
+            for(i_=0; i_<=clen-1;i_++)
+            {
+                c.c[i_] = ra[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Bicubic spline resampling
+
+        Input parameters:
+            A           -   function values at the old grid,
+                            array[0..OldHeight-1, 0..OldWidth-1]
+            OldHeight   -   old grid height, OldHeight>1
+            OldWidth    -   old grid width, OldWidth>1
+            NewHeight   -   new grid height, NewHeight>1
+            NewWidth    -   new grid width, NewWidth>1
+            
+        Output parameters:
+            B           -   function values at the new grid,
+                            array[0..NewHeight-1, 0..NewWidth-1]
+
+          -- ALGLIB routine --
+             15 May, 2007
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dresamplebicubic(ref double[,] a,
+            int oldheight,
+            int oldwidth,
+            ref double[,] b,
+            int newheight,
+            int newwidth)
+        {
+            double[,] buf = new double[0,0];
+            double[] x = new double[0];
+            double[] y = new double[0];
+            spline1d.spline1dinterpolant c = new spline1d.spline1dinterpolant();
+            int i = 0;
+            int j = 0;
+            int mw = 0;
+            int mh = 0;
+
+            System.Diagnostics.Debug.Assert(oldwidth>1 & oldheight>1, "Spline2DResampleBicubic: width/height less than 1");
+            System.Diagnostics.Debug.Assert(newwidth>1 & newheight>1, "Spline2DResampleBicubic: width/height less than 1");
+            
+            //
+            // Prepare
+            //
+            mw = Math.Max(oldwidth, newwidth);
+            mh = Math.Max(oldheight, newheight);
+            b = new double[newheight-1+1, newwidth-1+1];
+            buf = new double[oldheight-1+1, newwidth-1+1];
+            x = new double[Math.Max(mw, mh)-1+1];
+            y = new double[Math.Max(mw, mh)-1+1];
+            
+            //
+            // 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
+                //
+                spline1d.spline1dbuildcubic(x, y, oldwidth, 0, 0.0, 0, 0.0, ref c);
+                for(j=0; j<=newwidth-1; j++)
+                {
+                    buf[i,j] = spline1d.spline1dcalc(ref 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
+                //
+                spline1d.spline1dbuildcubic(x, y, oldheight, 0, 0.0, 0, 0.0, ref c);
+                for(i=0; i<=newheight-1; i++)
+                {
+                    b[i,j] = spline1d.spline1dcalc(ref 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]
+
+          -- ALGLIB routine --
+             09.07.2007
+             Copyright by Bochkanov Sergey
+        *************************************************************************/
+        public static void spline2dresamplebilinear(ref double[,] a,
+            int oldheight,
+            int oldwidth,
+            ref double[,] b,
+            int newheight,
+            int newwidth)
+        {
+            int i = 0;
+            int j = 0;
+            int l = 0;
+            int c = 0;
+            double t = 0;
+            double u = 0;
+
+            b = new double[newheight-1+1, newwidth-1+1];
+            for(i=0; i<=newheight-1; i++)
+            {
+                for(j=0; j<=newwidth-1; j++)
+                {
+                    l = i*(oldheight-1)/(newheight-1);
+                    if( l==oldheight-1 )
+                    {
+                        l = oldheight-2;
+                    }
+                    u = (double)(i)/((double)(newheight-1))*(oldheight-1)-l;
+                    c = j*(oldwidth-1)/(newwidth-1);
+                    if( c==oldwidth-1 )
+                    {
+                        c = oldwidth-2;
+                    }
+                    t = (double)(j*(oldwidth-1))/((double)(newwidth-1))-c;
+                    b[i,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.
+        *************************************************************************/
+        private static void bicubiccalcderivatives(ref double[,] a,
+            ref double[] x,
+            ref double[] y,
+            int m,
+            int n,
+            ref double[,] dx,
+            ref double[,] dy,
+            ref double[,] dxy)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            double[] xt = new double[0];
+            double[] ft = new double[0];
+            double[] c = new double[0];
+            double s = 0;
+            double ds = 0;
+            double d2s = 0;
+            double v = 0;
+
+            dx = new double[m-1+1, n-1+1];
+            dy = new double[m-1+1, n-1+1];
+            dxy = new double[m-1+1, n-1+1];
+            
+            //
+            // dF/dX
+            //
+            xt = new double[n-1+1];
+            ft = new double[n-1+1];
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    xt[j] = x[j];
+                    ft[j] = a[i,j];
+                }
+                spline3.buildcubicspline(xt, ft, n, 0, 0.0, 0, 0.0, ref c);
+                for(j=0; j<=n-1; j++)
+                {
+                    spline3.splinedifferentiation(ref c, x[j], ref s, ref ds, ref d2s);
+                    dx[i,j] = ds;
+                }
+            }
+            
+            //
+            // dF/dY
+            //
+            xt = new double[m-1+1];
+            ft = new double[m-1+1];
+            for(j=0; j<=n-1; j++)
+            {
+                for(i=0; i<=m-1; i++)
+                {
+                    xt[i] = y[i];
+                    ft[i] = a[i,j];
+                }
+                spline3.buildcubicspline(xt, ft, m, 0, 0.0, 0, 0.0, ref c);
+                for(i=0; i<=m-1; i++)
+                {
+                    spline3.splinedifferentiation(ref c, y[i], ref s, ref ds, ref d2s);
+                    dy[i,j] = ds;
+                }
+            }
+            
+            //
+            // d2F/dXdY
+            //
+            xt = new double[n-1+1];
+            ft = new double[n-1+1];
+            for(i=0; i<=m-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    xt[j] = x[j];
+                    ft[j] = dy[i,j];
+                }
+                spline3.buildcubicspline(xt, ft, n, 0, 0.0, 0, 0.0, ref c);
+                for(j=0; j<=n-1; j++)
+                {
+                    spline3.splinedifferentiation(ref c, x[j], ref s, ref ds, ref d2s);
+                    dxy[i,j] = ds;
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline3.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline3.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/spline3.cs	(revision 2645)
@@ -0,0 +1,1076 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class spline3
+    {
+        public static void buildlinearspline(double[] x,
+            double[] y,
+            int n,
+            ref double[] c)
+        {
+            int i = 0;
+            int tblsize = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2, "BuildLinearSpline: N<2!");
+            
+            //
+            // Sort points
+            //
+            heapsortpoints(ref x, ref y, n);
+            
+            //
+            // Fill C:
+            //  C[0]            -   length(C)
+            //  C[1]            -   type(C):
+            //                      3 - general cubic spline
+            //  C[2]            -   N
+            //  C[3]...C[3+N-1] -   x[i], i = 0...N-1
+            //  C[3+N]...C[3+N+(N-1)*4-1] - coefficients table
+            //
+            tblsize = 3+n+(n-1)*4;
+            c = new double[tblsize-1+1];
+            c[0] = tblsize;
+            c[1] = 3;
+            c[2] = n;
+            for(i=0; i<=n-1; i++)
+            {
+                c[3+i] = x[i];
+            }
+            for(i=0; i<=n-2; i++)
+            {
+                c[3+n+4*i+0] = y[i];
+                c[3+n+4*i+1] = (y[i+1]-y[i])/(x[i+1]-x[i]);
+                c[3+n+4*i+2] = 0;
+                c[3+n+4*i+3] = 0;
+            }
+        }
+
+
+        public static void buildcubicspline(double[] x,
+            double[] y,
+            int n,
+            int boundltype,
+            double boundl,
+            int boundrtype,
+            double boundr,
+            ref double[] c)
+        {
+            double[] a1 = new double[0];
+            double[] a2 = new double[0];
+            double[] a3 = new double[0];
+            double[] b = new double[0];
+            double[] d = new double[0];
+            int i = 0;
+            int tblsize = 0;
+            double delta = 0;
+            double delta2 = 0;
+            double delta3 = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2, "BuildCubicSpline: N<2!");
+            System.Diagnostics.Debug.Assert(boundltype==0 | boundltype==1 | boundltype==2, "BuildCubicSpline: incorrect BoundLType!");
+            System.Diagnostics.Debug.Assert(boundrtype==0 | boundrtype==1 | boundrtype==2, "BuildCubicSpline: incorrect BoundRType!");
+            a1 = new double[n-1+1];
+            a2 = new double[n-1+1];
+            a3 = new double[n-1+1];
+            b = new double[n-1+1];
+            
+            //
+            // Special case:
+            // * N=2
+            // * parabolic terminated boundary condition on both ends
+            //
+            if( n==2 & boundltype==0 & boundrtype==0 )
+            {
+                
+                //
+                // Change task type
+                //
+                boundltype = 2;
+                boundl = 0;
+                boundrtype = 2;
+                boundr = 0;
+            }
+            
+            //
+            //
+            // Sort points
+            //
+            heapsortpoints(ref x, ref y, n);
+            
+            //
+            // Left boundary conditions
+            //
+            if( boundltype==0 )
+            {
+                a1[0] = 0;
+                a2[0] = 1;
+                a3[0] = 1;
+                b[0] = 2*(y[1]-y[0])/(x[1]-x[0]);
+            }
+            if( boundltype==1 )
+            {
+                a1[0] = 0;
+                a2[0] = 1;
+                a3[0] = 0;
+                b[0] = boundl;
+            }
+            if( boundltype==2 )
+            {
+                a1[0] = 0;
+                a2[0] = 2;
+                a3[0] = 1;
+                b[0] = 3*(y[1]-y[0])/(x[1]-x[0])-0.5*boundl*(x[1]-x[0]);
+            }
+            
+            //
+            // Central conditions
+            //
+            for(i=1; i<=n-2; i++)
+            {
+                a1[i] = x[i+1]-x[i];
+                a2[i] = 2*(x[i+1]-x[i-1]);
+                a3[i] = x[i]-x[i-1];
+                b[i] = 3*(y[i]-y[i-1])/(x[i]-x[i-1])*(x[i+1]-x[i])+3*(y[i+1]-y[i])/(x[i+1]-x[i])*(x[i]-x[i-1]);
+            }
+            
+            //
+            // Right boundary conditions
+            //
+            if( boundrtype==0 )
+            {
+                a1[n-1] = 1;
+                a2[n-1] = 1;
+                a3[n-1] = 0;
+                b[n-1] = 2*(y[n-1]-y[n-2])/(x[n-1]-x[n-2]);
+            }
+            if( boundrtype==1 )
+            {
+                a1[n-1] = 0;
+                a2[n-1] = 1;
+                a3[n-1] = 0;
+                b[n-1] = boundr;
+            }
+            if( boundrtype==2 )
+            {
+                a1[n-1] = 1;
+                a2[n-1] = 2;
+                a3[n-1] = 0;
+                b[n-1] = 3*(y[n-1]-y[n-2])/(x[n-1]-x[n-2])+0.5*boundr*(x[n-1]-x[n-2]);
+            }
+            
+            //
+            // Solve
+            //
+            solvetridiagonal(a1, a2, a3, b, n, ref d);
+            
+            //
+            // Now problem is reduced to the cubic Hermite spline
+            //
+            buildhermitespline(x, y, d, n, ref c);
+        }
+
+
+        public static void buildhermitespline(double[] x,
+            double[] y,
+            double[] d,
+            int n,
+            ref double[] c)
+        {
+            int i = 0;
+            int tblsize = 0;
+            double delta = 0;
+            double delta2 = 0;
+            double delta3 = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+            d = (double[])d.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=2, "BuildHermiteSpline: N<2!");
+            
+            //
+            // Sort points
+            //
+            heapsortdpoints(ref x, ref y, ref d, n);
+            
+            //
+            // Fill C:
+            //  C[0]            -   length(C)
+            //  C[1]            -   type(C):
+            //                      3 - general cubic spline
+            //  C[2]            -   N
+            //  C[3]...C[3+N-1] -   x[i], i = 0...N-1
+            //  C[3+N]...C[3+N+(N-1)*4-1] - coefficients table
+            //
+            tblsize = 3+n+(n-1)*4;
+            c = new double[tblsize-1+1];
+            c[0] = tblsize;
+            c[1] = 3;
+            c[2] = n;
+            for(i=0; i<=n-1; i++)
+            {
+                c[3+i] = x[i];
+            }
+            for(i=0; i<=n-2; i++)
+            {
+                delta = x[i+1]-x[i];
+                delta2 = AP.Math.Sqr(delta);
+                delta3 = delta*delta2;
+                c[3+n+4*i+0] = y[i];
+                c[3+n+4*i+1] = d[i];
+                c[3+n+4*i+2] = (3*(y[i+1]-y[i])-2*d[i]*delta-d[i+1]*delta)/delta2;
+                c[3+n+4*i+3] = (2*(y[i]-y[i+1])+d[i]*delta+d[i+1]*delta)/delta3;
+            }
+        }
+
+
+        public static void buildakimaspline(double[] x,
+            double[] y,
+            int n,
+            ref double[] c)
+        {
+            int i = 0;
+            double[] d = new double[0];
+            double[] w = new double[0];
+            double[] diff = new double[0];
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            System.Diagnostics.Debug.Assert(n>=5, "BuildAkimaSpline: N<5!");
+            
+            //
+            // Sort points
+            //
+            heapsortpoints(ref x, ref y, n);
+            
+            //
+            // Prepare W (weights), Diff (divided differences)
+            //
+            w = new double[n-2+1];
+            diff = new double[n-2+1];
+            for(i=0; i<=n-2; i++)
+            {
+                diff[i] = (y[i+1]-y[i])/(x[i+1]-x[i]);
+            }
+            for(i=1; i<=n-2; i++)
+            {
+                w[i] = Math.Abs(diff[i]-diff[i-1]);
+            }
+            
+            //
+            // Prepare Hermite interpolation scheme
+            //
+            d = new double[n-1+1];
+            for(i=2; i<=n-3; i++)
+            {
+                if( (double)(Math.Abs(w[i-1])+Math.Abs(w[i+1]))!=(double)(0) )
+                {
+                    d[i] = (w[i+1]*diff[i-1]+w[i-1]*diff[i])/(w[i+1]+w[i-1]);
+                }
+                else
+                {
+                    d[i] = ((x[i+1]-x[i])*diff[i-1]+(x[i]-x[i-1])*diff[i])/(x[i+1]-x[i-1]);
+                }
+            }
+            d[0] = diffthreepoint(x[0], x[0], y[0], x[1], y[1], x[2], y[2]);
+            d[1] = diffthreepoint(x[1], x[0], y[0], x[1], y[1], x[2], y[2]);
+            d[n-2] = diffthreepoint(x[n-2], x[n-3], y[n-3], x[n-2], y[n-2], x[n-1], y[n-1]);
+            d[n-1] = diffthreepoint(x[n-1], x[n-3], y[n-3], x[n-2], y[n-2], x[n-1], y[n-1]);
+            
+            //
+            // Build Akima spline using Hermite interpolation scheme
+            //
+            buildhermitespline(x, y, d, n, ref c);
+        }
+
+
+        public static double splineinterpolation(ref double[] c,
+            double x)
+        {
+            double result = 0;
+            int n = 0;
+            int l = 0;
+            int r = 0;
+            int m = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c[1])==3, "SplineInterpolation: incorrect C!");
+            n = (int)Math.Round(c[2]);
+            
+            //
+            // Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
+            //
+            l = 3;
+            r = 3+n-2+1;
+            while( l!=r-1 )
+            {
+                m = (l+r)/2;
+                if( (double)(c[m])>=(double)(x) )
+                {
+                    r = m;
+                }
+                else
+                {
+                    l = m;
+                }
+            }
+            
+            //
+            // Interpolation
+            //
+            x = x-c[l];
+            m = 3+n+4*(l-3);
+            result = c[m]+x*(c[m+1]+x*(c[m+2]+x*c[m+3]));
+            return result;
+        }
+
+
+        public static void splinedifferentiation(ref double[] c,
+            double x,
+            ref double s,
+            ref double ds,
+            ref double d2s)
+        {
+            int n = 0;
+            int l = 0;
+            int r = 0;
+            int m = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c[1])==3, "SplineInterpolation: incorrect C!");
+            n = (int)Math.Round(c[2]);
+            
+            //
+            // Binary search
+            //
+            l = 3;
+            r = 3+n-2+1;
+            while( l!=r-1 )
+            {
+                m = (l+r)/2;
+                if( (double)(c[m])>=(double)(x) )
+                {
+                    r = m;
+                }
+                else
+                {
+                    l = m;
+                }
+            }
+            
+            //
+            // Differentiation
+            //
+            x = x-c[l];
+            m = 3+n+4*(l-3);
+            s = c[m]+x*(c[m+1]+x*(c[m+2]+x*c[m+3]));
+            ds = c[m+1]+2*x*c[m+2]+3*AP.Math.Sqr(x)*c[m+3];
+            d2s = 2*c[m+2]+6*x*c[m+3];
+        }
+
+
+        public static void splinecopy(ref double[] c,
+            ref double[] cc)
+        {
+            int s = 0;
+            int i_ = 0;
+
+            s = (int)Math.Round(c[0]);
+            cc = new double[s-1+1];
+            for(i_=0; i_<=s-1;i_++)
+            {
+                cc[i_] = c[i_];
+            }
+        }
+
+
+        public static void splineunpack(ref double[] c,
+            ref int n,
+            ref double[,] tbl)
+        {
+            int i = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c[1])==3, "SplineUnpack: incorrect C!");
+            n = (int)Math.Round(c[2]);
+            tbl = new double[n-2+1, 5+1];
+            
+            //
+            // Fill
+            //
+            for(i=0; i<=n-2; i++)
+            {
+                tbl[i,0] = c[3+i];
+                tbl[i,1] = c[3+i+1];
+                tbl[i,2] = c[3+n+4*i];
+                tbl[i,3] = c[3+n+4*i+1];
+                tbl[i,4] = c[3+n+4*i+2];
+                tbl[i,5] = c[3+n+4*i+3];
+            }
+        }
+
+
+        public static void splinelintransx(ref double[] c,
+            double a,
+            double b)
+        {
+            int i = 0;
+            int n = 0;
+            double v = 0;
+            double dv = 0;
+            double d2v = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[] d = new double[0];
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c[1])==3, "SplineLinTransX: incorrect C!");
+            n = (int)Math.Round(c[2]);
+            
+            //
+            // Special case: A=0
+            //
+            if( (double)(a)==(double)(0) )
+            {
+                v = splineinterpolation(ref c, b);
+                for(i=0; i<=n-2; i++)
+                {
+                    c[3+n+4*i] = v;
+                    c[3+n+4*i+1] = 0;
+                    c[3+n+4*i+2] = 0;
+                    c[3+n+4*i+3] = 0;
+                }
+                return;
+            }
+            
+            //
+            // General case: A<>0.
+            // Unpack, X, Y, dY/dX.
+            // Scale and pack again.
+            //
+            x = new double[n-1+1];
+            y = new double[n-1+1];
+            d = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                x[i] = c[3+i];
+                splinedifferentiation(ref c, x[i], ref v, ref dv, ref d2v);
+                x[i] = (x[i]-b)/a;
+                y[i] = v;
+                d[i] = a*dv;
+            }
+            buildhermitespline(x, y, d, n, ref c);
+        }
+
+
+        public static void splinelintransy(ref double[] c,
+            double a,
+            double b)
+        {
+            int i = 0;
+            int n = 0;
+            double v = 0;
+            double dv = 0;
+            double d2v = 0;
+            double[] x = new double[0];
+            double[] y = new double[0];
+            double[] d = new double[0];
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c[1])==3, "SplineLinTransX: incorrect C!");
+            n = (int)Math.Round(c[2]);
+            
+            //
+            // Special case: A=0
+            //
+            for(i=0; i<=n-2; i++)
+            {
+                c[3+n+4*i] = a*c[3+n+4*i]+b;
+                c[3+n+4*i+1] = a*c[3+n+4*i+1];
+                c[3+n+4*i+2] = a*c[3+n+4*i+2];
+                c[3+n+4*i+3] = a*c[3+n+4*i+3];
+            }
+        }
+
+
+        public static double splineintegration(ref double[] c,
+            double x)
+        {
+            double result = 0;
+            int n = 0;
+            int i = 0;
+            int l = 0;
+            int r = 0;
+            int m = 0;
+            double w = 0;
+
+            System.Diagnostics.Debug.Assert((int)Math.Round(c[1])==3, "SplineIntegration: incorrect C!");
+            n = (int)Math.Round(c[2]);
+            
+            //
+            // Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
+            //
+            l = 3;
+            r = 3+n-2+1;
+            while( l!=r-1 )
+            {
+                m = (l+r)/2;
+                if( (double)(c[m])>=(double)(x) )
+                {
+                    r = m;
+                }
+                else
+                {
+                    l = m;
+                }
+            }
+            
+            //
+            // Integration
+            //
+            result = 0;
+            for(i=3; i<=l-1; i++)
+            {
+                w = c[i+1]-c[i];
+                m = 3+n+4*(i-3);
+                result = result+c[m]*w;
+                result = result+c[m+1]*AP.Math.Sqr(w)/2;
+                result = result+c[m+2]*AP.Math.Sqr(w)*w/3;
+                result = result+c[m+3]*AP.Math.Sqr(AP.Math.Sqr(w))/4;
+            }
+            w = x-c[l];
+            m = 3+n+4*(l-3);
+            result = result+c[m]*w;
+            result = result+c[m+1]*AP.Math.Sqr(w)/2;
+            result = result+c[m+2]*AP.Math.Sqr(w)*w/3;
+            result = result+c[m+3]*AP.Math.Sqr(AP.Math.Sqr(w))/4;
+            return result;
+        }
+
+
+        public static void spline3buildtable(int n,
+            int diffn,
+            double[] x,
+            double[] y,
+            double boundl,
+            double boundr,
+            ref double[,] ctbl)
+        {
+            bool c = new bool();
+            int e = 0;
+            int g = 0;
+            double tmp = 0;
+            int nxm1 = 0;
+            int i = 0;
+            int j = 0;
+            double dx = 0;
+            double dxj = 0;
+            double dyj = 0;
+            double dxjp1 = 0;
+            double dyjp1 = 0;
+            double dxp = 0;
+            double dyp = 0;
+            double yppa = 0;
+            double yppb = 0;
+            double pj = 0;
+            double b1 = 0;
+            double b2 = 0;
+            double b3 = 0;
+            double b4 = 0;
+
+            x = (double[])x.Clone();
+            y = (double[])y.Clone();
+
+            n = n-1;
+            g = (n+1)/2;
+            do
+            {
+                i = g;
+                do
+                {
+                    j = i-g;
+                    c = true;
+                    do
+                    {
+                        if( (double)(x[j])<=(double)(x[j+g]) )
+                        {
+                            c = false;
+                        }
+                        else
+                        {
+                            tmp = x[j];
+                            x[j] = x[j+g];
+                            x[j+g] = tmp;
+                            tmp = y[j];
+                            y[j] = y[j+g];
+                            y[j+g] = tmp;
+                        }
+                        j = j-1;
+                    }
+                    while( j>=0 & c );
+                    i = i+1;
+                }
+                while( i<=n );
+                g = g/2;
+            }
+            while( g>0 );
+            ctbl = new double[4+1, n+1];
+            n = n+1;
+            if( diffn==1 )
+            {
+                b1 = 1;
+                b2 = 6/(x[1]-x[0])*((y[1]-y[0])/(x[1]-x[0])-boundl);
+                b3 = 1;
+                b4 = 6/(x[n-1]-x[n-2])*(boundr-(y[n-1]-y[n-2])/(x[n-1]-x[n-2]));
+            }
+            else
+            {
+                b1 = 0;
+                b2 = 2*boundl;
+                b3 = 0;
+                b4 = 2*boundr;
+            }
+            nxm1 = n-1;
+            if( n>=2 )
+            {
+                if( n>2 )
+                {
+                    dxj = x[1]-x[0];
+                    dyj = y[1]-y[0];
+                    j = 2;
+                    while( j<=nxm1 )
+                    {
+                        dxjp1 = x[j]-x[j-1];
+                        dyjp1 = y[j]-y[j-1];
+                        dxp = dxj+dxjp1;
+                        ctbl[1,j-1] = dxjp1/dxp;
+                        ctbl[2,j-1] = 1-ctbl[1,j-1];
+                        ctbl[3,j-1] = 6*(dyjp1/dxjp1-dyj/dxj)/dxp;
+                        dxj = dxjp1;
+                        dyj = dyjp1;
+                        j = j+1;
+                    }
+                }
+                ctbl[1,0] = -(b1/2);
+                ctbl[2,0] = b2/2;
+                if( n!=2 )
+                {
+                    j = 2;
+                    while( j<=nxm1 )
+                    {
+                        pj = ctbl[2,j-1]*ctbl[1,j-2]+2;
+                        ctbl[1,j-1] = -(ctbl[1,j-1]/pj);
+                        ctbl[2,j-1] = (ctbl[3,j-1]-ctbl[2,j-1]*ctbl[2,j-2])/pj;
+                        j = j+1;
+                    }
+                }
+                yppb = (b4-b3*ctbl[2,nxm1-1])/(b3*ctbl[1,nxm1-1]+2);
+                i = 1;
+                while( i<=nxm1 )
+                {
+                    j = n-i;
+                    yppa = ctbl[1,j-1]*yppb+ctbl[2,j-1];
+                    dx = x[j]-x[j-1];
+                    ctbl[3,j-1] = (yppb-yppa)/dx/6;
+                    ctbl[2,j-1] = yppa/2;
+                    ctbl[1,j-1] = (y[j]-y[j-1])/dx-(ctbl[2,j-1]+ctbl[3,j-1]*dx)*dx;
+                    yppb = yppa;
+                    i = i+1;
+                }
+                for(i=1; i<=n; i++)
+                {
+                    ctbl[0,i-1] = y[i-1];
+                    ctbl[4,i-1] = x[i-1];
+                }
+            }
+        }
+
+
+        public static double spline3interpolate(int n,
+            ref double[,] c,
+            double x)
+        {
+            double result = 0;
+            int i = 0;
+            int l = 0;
+            int half = 0;
+            int first = 0;
+            int middle = 0;
+
+            n = n-1;
+            l = n;
+            first = 0;
+            while( l>0 )
+            {
+                half = l/2;
+                middle = first+half;
+                if( (double)(c[4,middle])<(double)(x) )
+                {
+                    first = middle+1;
+                    l = l-half-1;
+                }
+                else
+                {
+                    l = half;
+                }
+            }
+            i = first-1;
+            if( i<0 )
+            {
+                i = 0;
+            }
+            result = c[0,i]+(x-c[4,i])*(c[1,i]+(x-c[4,i])*(c[2,i]+c[3,i]*(x-c[4,i])));
+            return result;
+        }
+
+
+        private static void heapsortpoints(ref double[] x,
+            ref double[] y,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            bool isascending = new bool();
+            bool isdescending = new bool();
+
+            
+            //
+            // Test for already sorted set
+            //
+            isascending = true;
+            isdescending = true;
+            for(i=1; i<=n-1; i++)
+            {
+                isascending = isascending & (double)(x[i])>(double)(x[i-1]);
+                isdescending = isdescending & (double)(x[i])<(double)(x[i-1]);
+            }
+            if( isascending )
+            {
+                return;
+            }
+            if( isdescending )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    j = n-1-i;
+                    if( j<=i )
+                    {
+                        break;
+                    }
+                    tmp = x[i];
+                    x[i] = x[j];
+                    x[j] = tmp;
+                    tmp = y[i];
+                    y[i] = y[j];
+                    y[j] = tmp;
+                }
+                return;
+            }
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                return;
+            }
+            
+            //
+            // General case
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(x[k-1])>=(double)(x[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = x[k-1];
+                        x[k-1] = x[t-1];
+                        x[t-1] = tmp;
+                        tmp = y[k-1];
+                        y[k-1] = y[t-1];
+                        y[t-1] = tmp;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = x[i];
+                x[i] = x[0];
+                x[0] = tmp;
+                tmp = y[i];
+                y[i] = y[0];
+                y[0] = tmp;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(x[k])>(double)(x[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(x[t-1])>=(double)(x[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = x[k-1];
+                            x[k-1] = x[t-1];
+                            x[t-1] = tmp;
+                            tmp = y[k-1];
+                            y[k-1] = y[t-1];
+                            y[t-1] = tmp;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+
+
+        private static void heapsortdpoints(ref double[] x,
+            ref double[] y,
+            ref double[] d,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            bool isascending = new bool();
+            bool isdescending = new bool();
+
+            
+            //
+            // Test for already sorted set
+            //
+            isascending = true;
+            isdescending = true;
+            for(i=1; i<=n-1; i++)
+            {
+                isascending = isascending & (double)(x[i])>(double)(x[i-1]);
+                isdescending = isdescending & (double)(x[i])<(double)(x[i-1]);
+            }
+            if( isascending )
+            {
+                return;
+            }
+            if( isdescending )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    j = n-1-i;
+                    if( j<=i )
+                    {
+                        break;
+                    }
+                    tmp = x[i];
+                    x[i] = x[j];
+                    x[j] = tmp;
+                    tmp = y[i];
+                    y[i] = y[j];
+                    y[j] = tmp;
+                    tmp = d[i];
+                    d[i] = d[j];
+                    d[j] = tmp;
+                }
+                return;
+            }
+            
+            //
+            // Special case: N=1
+            //
+            if( n==1 )
+            {
+                return;
+            }
+            
+            //
+            // General case
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(x[k-1])>=(double)(x[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = x[k-1];
+                        x[k-1] = x[t-1];
+                        x[t-1] = tmp;
+                        tmp = y[k-1];
+                        y[k-1] = y[t-1];
+                        y[t-1] = tmp;
+                        tmp = d[k-1];
+                        d[k-1] = d[t-1];
+                        d[t-1] = tmp;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = x[i];
+                x[i] = x[0];
+                x[0] = tmp;
+                tmp = y[i];
+                y[i] = y[0];
+                y[0] = tmp;
+                tmp = d[i];
+                d[i] = d[0];
+                d[0] = tmp;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(x[k])>(double)(x[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(x[t-1])>=(double)(x[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = x[k-1];
+                            x[k-1] = x[t-1];
+                            x[t-1] = tmp;
+                            tmp = y[k-1];
+                            y[k-1] = y[t-1];
+                            y[t-1] = tmp;
+                            tmp = d[k-1];
+                            d[k-1] = d[t-1];
+                            d[t-1] = tmp;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+
+
+        private static void solvetridiagonal(double[] a,
+            double[] b,
+            double[] c,
+            double[] d,
+            int n,
+            ref double[] x)
+        {
+            int k = 0;
+            double t = 0;
+
+            a = (double[])a.Clone();
+            b = (double[])b.Clone();
+            c = (double[])c.Clone();
+            d = (double[])d.Clone();
+
+            x = new double[n-1+1];
+            a[0] = 0;
+            c[n-1] = 0;
+            for(k=1; k<=n-1; k++)
+            {
+                t = a[k]/b[k-1];
+                b[k] = b[k]-t*c[k-1];
+                d[k] = d[k]-t*d[k-1];
+            }
+            x[n-1] = d[n-1]/b[n-1];
+            for(k=n-2; k>=0; k--)
+            {
+                x[k] = (d[k]-c[k]*x[k+1])/b[k];
+            }
+        }
+
+
+        private static double diffthreepoint(double t,
+            double x0,
+            double f0,
+            double x1,
+            double f1,
+            double x2,
+            double f2)
+        {
+            double result = 0;
+            double a = 0;
+            double b = 0;
+
+            t = t-x0;
+            x1 = x1-x0;
+            x2 = x2-x0;
+            a = (f2-f0-x2/x1*(f1-f0))/(AP.Math.Sqr(x2)-x1*x2);
+            b = (f1-f0-a*AP.Math.Sqr(x1))/x1;
+            result = 2*a*t+b;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/srcond.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/srcond.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/srcond.cs	(revision 2645)
@@ -0,0 +1,631 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class srcond
+    {
+        /*************************************************************************
+        Condition number estimate of a symmetric 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 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 definite matrix which is given by its upper or
+                        lower triangle depending on IsUpper.
+                        Array with elements [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   storage format.
+
+        Result:
+            1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double smatrixrcond(ref double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double[,] a1 = new double[0,0];
+
+            a1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                if( isupper )
+                {
+                    for(j=i; j<=n; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+                else
+                {
+                    for(j=1; j<=i; j++)
+                    {
+                        a1[i,j] = a[i-1,j-1];
+                    }
+                }
+            }
+            result = rcondsymmetric(a1, n, isupper);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Condition number estimate of a matrix given by LDLT-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:
+            L       -   LDLT-decomposition of matrix A given by the upper or lower
+                        triangle depending on IsUpper.
+                        Output of SMatrixLDLT subroutine.
+            Pivots  -   table of permutations which were made during LDLT-decomposition,
+                        Output of SMatrixLDLT subroutine.
+            N       -   size of matrix A.
+            IsUpper -   storage format.
+
+        Result:
+            1/LowerBound(cond(A))
+        *************************************************************************/
+        public static double smatrixldltrcond(ref double[,] l,
+            ref int[] pivots,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            double[,] l1 = new double[0,0];
+            int[] p1 = new int[0];
+
+            l1 = new double[n+1, n+1];
+            for(i=1; i<=n; i++)
+            {
+                if( isupper )
+                {
+                    for(j=i; j<=n; j++)
+                    {
+                        l1[i,j] = l[i-1,j-1];
+                    }
+                }
+                else
+                {
+                    for(j=1; j<=i; j++)
+                    {
+                        l1[i,j] = l[i-1,j-1];
+                    }
+                }
+            }
+            p1 = new int[n+1];
+            for(i=1; i<=n; i++)
+            {
+                if( pivots[i-1]>=0 )
+                {
+                    p1[i] = pivots[i-1]+1;
+                }
+                else
+                {
+                    p1[i] = -(pivots[i-1]+n+1);
+                }
+            }
+            result = rcondldlt(ref l1, ref p1, n, isupper);
+            return result;
+        }
+
+
+        public static double rcondsymmetric(double[,] a,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            int i = 0;
+            int j = 0;
+            int im = 0;
+            int jm = 0;
+            double v = 0;
+            double nrm = 0;
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            nrm = 0;
+            for(j=1; j<=n; j++)
+            {
+                v = 0;
+                for(i=1; i<=n; i++)
+                {
+                    im = i;
+                    jm = j;
+                    if( isupper & j<i )
+                    {
+                        im = j;
+                        jm = i;
+                    }
+                    if( !isupper & j>i )
+                    {
+                        im = j;
+                        jm = i;
+                    }
+                    v = v+Math.Abs(a[im,jm]);
+                }
+                nrm = Math.Max(nrm, v);
+            }
+            ldlt.ldltdecomposition(ref a, n, isupper, ref pivots);
+            internalldltrcond(ref a, ref pivots, n, isupper, true, nrm, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static double rcondldlt(ref double[,] l,
+            ref int[] pivots,
+            int n,
+            bool isupper)
+        {
+            double result = 0;
+            double v = 0;
+
+            internalldltrcond(ref l, ref pivots, n, isupper, false, 0, ref v);
+            result = v;
+            return result;
+        }
+
+
+        public static void internalldltrcond(ref double[,] l,
+            ref int[] pivots,
+            int n,
+            bool isupper,
+            bool isnormprovided,
+            double anorm,
+            ref double rcond)
+        {
+            int i = 0;
+            int ix = 0;
+            int kase = 0;
+            int k = 0;
+            int km1 = 0;
+            int km2 = 0;
+            int kp1 = 0;
+            int kp2 = 0;
+            double ainvnm = 0;
+            double[] work0 = new double[0];
+            double[] work1 = new double[0];
+            double[] work2 = new double[0];
+            int[] iwork = new int[0];
+            double v = 0;
+            int i_ = 0;
+
+            System.Diagnostics.Debug.Assert(n>=0);
+            
+            //
+            // Check that the diagonal matrix D is nonsingular.
+            //
+            rcond = 0;
+            if( isupper )
+            {
+                for(i=n; i>=1; i--)
+                {
+                    if( pivots[i]>0 & (double)(l[i,i])==(double)(0) )
+                    {
+                        return;
+                    }
+                }
+            }
+            else
+            {
+                for(i=1; i<=n; i++)
+                {
+                    if( pivots[i]>0 & (double)(l[i,i])==(double)(0) )
+                    {
+                        return;
+                    }
+                }
+            }
+            
+            //
+            // Estimate the norm of A.
+            //
+            if( !isnormprovided )
+            {
+                kase = 0;
+                anorm = 0;
+                while( true )
+                {
+                    estnorm.iterativeestimate1norm(n, ref work1, ref work0, ref iwork, ref anorm, ref kase);
+                    if( kase==0 )
+                    {
+                        break;
+                    }
+                    if( isupper )
+                    {
+                        
+                        //
+                        // Multiply by U'
+                        //
+                        k = n;
+                        while( k>=1 )
+                        {
+                            if( pivots[k]>0 )
+                            {
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k];
+                                work0[k] = work0[pivots[k]];
+                                work0[pivots[k]] = v;
+                                
+                                //
+                                // U(k)
+                                //
+                                km1 = k-1;
+                                v = 0.0;
+                                for(i_=1; i_<=km1;i_++)
+                                {
+                                    v += work0[i_]*l[i_,k];
+                                }
+                                work0[k] = work0[k]+v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k-1;
+                            }
+                            else
+                            {
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k-1];
+                                work0[k-1] = work0[-pivots[k-1]];
+                                work0[-pivots[k-1]] = v;
+                                
+                                //
+                                // U(k)
+                                //
+                                km1 = k-1;
+                                km2 = k-2;
+                                v = 0.0;
+                                for(i_=1; i_<=km2;i_++)
+                                {
+                                    v += work0[i_]*l[i_,km1];
+                                }
+                                work0[km1] = work0[km1]+v;
+                                v = 0.0;
+                                for(i_=1; i_<=km2;i_++)
+                                {
+                                    v += work0[i_]*l[i_,k];
+                                }
+                                work0[k] = work0[k]+v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k-2;
+                            }
+                        }
+                        
+                        //
+                        // Multiply by D
+                        //
+                        k = n;
+                        while( k>=1 )
+                        {
+                            if( pivots[k]>0 )
+                            {
+                                work0[k] = work0[k]*l[k,k];
+                                k = k-1;
+                            }
+                            else
+                            {
+                                v = work0[k-1];
+                                work0[k-1] = l[k-1,k-1]*work0[k-1]+l[k-1,k]*work0[k];
+                                work0[k] = l[k-1,k]*v+l[k,k]*work0[k];
+                                k = k-2;
+                            }
+                        }
+                        
+                        //
+                        // Multiply by U
+                        //
+                        k = 1;
+                        while( k<=n )
+                        {
+                            if( pivots[k]>0 )
+                            {
+                                
+                                //
+                                // U(k)
+                                //
+                                km1 = k-1;
+                                v = work0[k];
+                                for(i_=1; i_<=km1;i_++)
+                                {
+                                    work0[i_] = work0[i_] + v*l[i_,k];
+                                }
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k];
+                                work0[k] = work0[pivots[k]];
+                                work0[pivots[k]] = v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k+1;
+                            }
+                            else
+                            {
+                                
+                                //
+                                // U(k)
+                                //
+                                km1 = k-1;
+                                kp1 = k+1;
+                                v = work0[k];
+                                for(i_=1; i_<=km1;i_++)
+                                {
+                                    work0[i_] = work0[i_] + v*l[i_,k];
+                                }
+                                v = work0[kp1];
+                                for(i_=1; i_<=km1;i_++)
+                                {
+                                    work0[i_] = work0[i_] + v*l[i_,kp1];
+                                }
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k];
+                                work0[k] = work0[-pivots[k]];
+                                work0[-pivots[k]] = v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k+2;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Multiply by L'
+                        //
+                        k = 1;
+                        while( k<=n )
+                        {
+                            if( pivots[k]>0 )
+                            {
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k];
+                                work0[k] = work0[pivots[k]];
+                                work0[pivots[k]] = v;
+                                
+                                //
+                                // L(k)
+                                //
+                                kp1 = k+1;
+                                v = 0.0;
+                                for(i_=kp1; i_<=n;i_++)
+                                {
+                                    v += work0[i_]*l[i_,k];
+                                }
+                                work0[k] = work0[k]+v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k+1;
+                            }
+                            else
+                            {
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k+1];
+                                work0[k+1] = work0[-pivots[k+1]];
+                                work0[-pivots[k+1]] = v;
+                                
+                                //
+                                // L(k)
+                                //
+                                kp1 = k+1;
+                                kp2 = k+2;
+                                v = 0.0;
+                                for(i_=kp2; i_<=n;i_++)
+                                {
+                                    v += work0[i_]*l[i_,k];
+                                }
+                                work0[k] = work0[k]+v;
+                                v = 0.0;
+                                for(i_=kp2; i_<=n;i_++)
+                                {
+                                    v += work0[i_]*l[i_,kp1];
+                                }
+                                work0[kp1] = work0[kp1]+v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k+2;
+                            }
+                        }
+                        
+                        //
+                        // Multiply by D
+                        //
+                        k = n;
+                        while( k>=1 )
+                        {
+                            if( pivots[k]>0 )
+                            {
+                                work0[k] = work0[k]*l[k,k];
+                                k = k-1;
+                            }
+                            else
+                            {
+                                v = work0[k-1];
+                                work0[k-1] = l[k-1,k-1]*work0[k-1]+l[k,k-1]*work0[k];
+                                work0[k] = l[k,k-1]*v+l[k,k]*work0[k];
+                                k = k-2;
+                            }
+                        }
+                        
+                        //
+                        // Multiply by L
+                        //
+                        k = n;
+                        while( k>=1 )
+                        {
+                            if( pivots[k]>0 )
+                            {
+                                
+                                //
+                                // L(k)
+                                //
+                                kp1 = k+1;
+                                v = work0[k];
+                                for(i_=kp1; i_<=n;i_++)
+                                {
+                                    work0[i_] = work0[i_] + v*l[i_,k];
+                                }
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k];
+                                work0[k] = work0[pivots[k]];
+                                work0[pivots[k]] = v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k-1;
+                            }
+                            else
+                            {
+                                
+                                //
+                                // L(k)
+                                //
+                                kp1 = k+1;
+                                km1 = k-1;
+                                v = work0[k];
+                                for(i_=kp1; i_<=n;i_++)
+                                {
+                                    work0[i_] = work0[i_] + v*l[i_,k];
+                                }
+                                v = work0[km1];
+                                for(i_=kp1; i_<=n;i_++)
+                                {
+                                    work0[i_] = work0[i_] + v*l[i_,km1];
+                                }
+                                
+                                //
+                                // P(k)
+                                //
+                                v = work0[k];
+                                work0[k] = work0[-pivots[k]];
+                                work0[-pivots[k]] = v;
+                                
+                                //
+                                // Next k
+                                //
+                                k = k-2;
+                            }
+                        }
+                    }
+                }
+            }
+            
+            //
+            // Quick return if possible
+            //
+            rcond = 0;
+            if( n==0 )
+            {
+                rcond = 1;
+                return;
+            }
+            if( (double)(anorm)==(double)(0) )
+            {
+                return;
+            }
+            
+            //
+            // Estimate the 1-norm of inv(A).
+            //
+            kase = 0;
+            while( true )
+            {
+                estnorm.iterativeestimate1norm(n, ref work1, ref work0, ref iwork, ref ainvnm, ref kase);
+                if( kase==0 )
+                {
+                    break;
+                }
+                ssolve.solvesystemldlt(ref l, ref pivots, work0, n, isupper, ref work2);
+                for(i_=1; i_<=n;i_++)
+                {
+                    work0[i_] = work2[i_];
+                }
+            }
+            
+            //
+            // Compute the estimate of the reciprocal condition number.
+            //
+            if( (double)(ainvnm)!=(double)(0) )
+            {
+                v = 1/ainvnm;
+                rcond = v/anorm;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ssolve.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ssolve.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/ssolve.cs	(revision 2645)
@@ -0,0 +1,980 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class ssolve
+    {
+        /*************************************************************************
+        Solving  a system  of linear equations  with a system matrix  given by its
+        LDLT decomposition
+
+        The algorithm solves systems with a square matrix only.
+
+        Input parameters:
+            A       -   LDLT decomposition of the matrix (the result of the
+                        SMatrixLDLT subroutine).
+            Pivots  -   row permutation table (the result of the SMatrixLDLT subroutine).
+            B       -   right side of a system.
+                        Array whose index ranges within [0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   points to the triangle of matrix A in which the LDLT
+                        decomposition is stored.
+                        If IsUpper=True, the decomposition has the form of U*D*U',
+                        matrix U is stored in the upper triangle of  matrix A  (in
+                        that case, the lower triangle isn't used and isn't changed
+                        by the subroutine).
+                        Similarly, if IsUpper=False, the decomposition has the form
+                        of L*D*L' and the lower triangle stores matrix L.
+
+        Output parameters:
+            X       -   solution of a system.
+                        Array whose index ranges within [0..N-1].
+
+        Result:
+            True, if the matrix is not singular. X contains the solution.
+            False, if the matrix is singular (the determinant of matrix D is equal
+        to 0). In this case, X doesn't contain a solution.
+        *************************************************************************/
+        public static bool smatrixldltsolve(ref double[,] a,
+            ref int[] pivots,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int kp = 0;
+            double ak = 0;
+            double akm1 = 0;
+            double akm1k = 0;
+            double bk = 0;
+            double bkm1 = 0;
+            double denom = 0;
+            double v = 0;
+            int i_ = 0;
+
+            b = (double[])b.Clone();
+
+            
+            //
+            // Quick return if possible
+            //
+            result = true;
+            if( n==0 )
+            {
+                return result;
+            }
+            
+            //
+            // Check that the diagonal matrix D is nonsingular
+            //
+            if( isupper )
+            {
+                
+                //
+                // Upper triangular storage: examine D from bottom to top
+                //
+                for(i=n-1; i>=0; i--)
+                {
+                    if( pivots[i]>=0 & (double)(a[i,i])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Lower triangular storage: examine D from top to bottom.
+                //
+                for(i=0; i<=n-1; i++)
+                {
+                    if( pivots[i]>=0 & (double)(a[i,i])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                }
+            }
+            
+            //
+            // Solve Ax = b
+            //
+            if( isupper )
+            {
+                
+                //
+                // Solve A*X = B, where A = U*D*U'.
+                //
+                // First solve U*D*X = B, overwriting B with X.
+                //
+                // K+1 is the main loop index, decreasing from N to 1 in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = n-1;
+                while( k>=0 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Interchange rows K+1 and IPIV(K+1).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(U(K+1)), where U(K+1) is the transformation
+                        // stored in column K+1 of A.
+                        //
+                        v = b[k];
+                        for(i_=0; i_<=k-1;i_++)
+                        {
+                            b[i_] = b[i_] - v*a[i_,k];
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        b[k] = b[k]/a[k,k];
+                        k = k-1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Interchange rows K+1-1 and -IPIV(K+1).
+                        //
+                        kp = pivots[k]+n;
+                        if( kp!=k-1 )
+                        {
+                            v = b[k-1];
+                            b[k-1] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(U(K+1)), where U(K+1) is the transformation
+                        // stored in columns K+1-1 and K+1 of A.
+                        //
+                        v = b[k];
+                        for(i_=0; i_<=k-2;i_++)
+                        {
+                            b[i_] = b[i_] - v*a[i_,k];
+                        }
+                        v = b[k-1];
+                        for(i_=0; i_<=k-2;i_++)
+                        {
+                            b[i_] = b[i_] - v*a[i_,k-1];
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        akm1k = a[k-1,k];
+                        akm1 = a[k-1,k-1]/akm1k;
+                        ak = a[k,k]/akm1k;
+                        denom = akm1*ak-1;
+                        bkm1 = b[k-1]/akm1k;
+                        bk = b[k]/akm1k;
+                        b[k-1] = (ak*bkm1-bk)/denom;
+                        b[k] = (akm1*bk-bkm1)/denom;
+                        k = k-2;
+                    }
+                }
+                
+                //
+                // Next solve U'*X = B, overwriting B with X.
+                //
+                // K+1 is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = 0;
+                while( k<=n-1 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Multiply by inv(U'(K+1)), where U(K+1) is the transformation
+                        // stored in column K+1 of A.
+                        //
+                        v = 0.0;
+                        for(i_=0; i_<=k-1;i_++)
+                        {
+                            v += b[i_]*a[i_,k];
+                        }
+                        b[k] = b[k]-v;
+                        
+                        //
+                        // Interchange rows K+1 and IPIV(K+1).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k+1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Multiply by inv(U'(K+1+1)), where U(K+1+1) is the transformation
+                        // stored in columns K+1 and K+1+1 of A.
+                        //
+                        v = 0.0;
+                        for(i_=0; i_<=k-1;i_++)
+                        {
+                            v += b[i_]*a[i_,k];
+                        }
+                        b[k] = b[k]-v;
+                        v = 0.0;
+                        for(i_=0; i_<=k-1;i_++)
+                        {
+                            v += b[i_]*a[i_,k+1];
+                        }
+                        b[k+1] = b[k+1]-v;
+                        
+                        //
+                        // Interchange rows K+1 and -IPIV(K+1).
+                        //
+                        kp = pivots[k]+n;
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k+2;
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Solve A*X = B, where A = L*D*L'.
+                //
+                // First solve L*D*X = B, overwriting B with X.
+                //
+                // K+1 is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = 0;
+                while( k<=n-1 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Interchange rows K+1 and IPIV(K+1).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(L(K+1)), where L(K+1) is the transformation
+                        // stored in column K+1 of A.
+                        //
+                        if( k+1<n )
+                        {
+                            v = b[k];
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                b[i_] = b[i_] - v*a[i_,k];
+                            }
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        b[k] = b[k]/a[k,k];
+                        k = k+1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Interchange rows K+1+1 and -IPIV(K+1).
+                        //
+                        kp = pivots[k]+n;
+                        if( kp!=k+1 )
+                        {
+                            v = b[k+1];
+                            b[k+1] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(L(K+1)), where L(K+1) is the transformation
+                        // stored in columns K+1 and K+1+1 of A.
+                        //
+                        if( k+1<n-1 )
+                        {
+                            v = b[k];
+                            for(i_=k+2; i_<=n-1;i_++)
+                            {
+                                b[i_] = b[i_] - v*a[i_,k];
+                            }
+                            v = b[k+1];
+                            for(i_=k+2; i_<=n-1;i_++)
+                            {
+                                b[i_] = b[i_] - v*a[i_,k+1];
+                            }
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        akm1k = a[k+1,k];
+                        akm1 = a[k,k]/akm1k;
+                        ak = a[k+1,k+1]/akm1k;
+                        denom = akm1*ak-1;
+                        bkm1 = b[k]/akm1k;
+                        bk = b[k+1]/akm1k;
+                        b[k] = (ak*bkm1-bk)/denom;
+                        b[k+1] = (akm1*bk-bkm1)/denom;
+                        k = k+2;
+                    }
+                }
+                
+                //
+                // Next solve L'*X = B, overwriting B with X.
+                //
+                // K+1 is the main loop index, decreasing from N to 1 in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = n-1;
+                while( k>=0 )
+                {
+                    if( pivots[k]>=0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Multiply by inv(L'(K+1)), where L(K+1) is the transformation
+                        // stored in column K+1 of A.
+                        //
+                        if( k+1<n )
+                        {
+                            v = 0.0;
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                v += b[i_]*a[i_,k];
+                            }
+                            b[k] = b[k]-v;
+                        }
+                        
+                        //
+                        // Interchange rows K+1 and IPIV(K+1).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k-1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Multiply by inv(L'(K+1-1)), where L(K+1-1) is the transformation
+                        // stored in columns K+1-1 and K+1 of A.
+                        //
+                        if( k+1<n )
+                        {
+                            v = 0.0;
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                v += b[i_]*a[i_,k];
+                            }
+                            b[k] = b[k]-v;
+                            v = 0.0;
+                            for(i_=k+1; i_<=n-1;i_++)
+                            {
+                                v += b[i_]*a[i_,k-1];
+                            }
+                            b[k-1] = b[k-1]-v;
+                        }
+                        
+                        //
+                        // Interchange rows K+1 and -IPIV(K+1).
+                        //
+                        kp = pivots[k]+n;
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k-2;
+                    }
+                }
+            }
+            x = new double[n-1+1];
+            for(i_=0; i_<=n-1;i_++)
+            {
+                x[i_] = b[i_];
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Solving a system of linear equations with a symmetric system matrix
+
+        Input parameters:
+            A       -   system matrix (upper or lower triangle).
+                        Array whose indexes range within [0..N-1, 0..N-1].
+            B       -   right side of a system.
+                        Array whose index ranges within [0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   If IsUpper = True, A contains the upper triangle,
+                        otherwise A contains the lower triangle.
+
+        Output parameters:
+            X       -   solution of a system.
+                        Array whose index ranges within [0..N-1].
+
+        Result:
+            True, if the matrix is not singular. X contains the solution.
+            False, if the matrix is singular (the determinant of the matrix is equal
+        to 0). In this case, X doesn't contain a solution.
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixsolve(double[,] a,
+            ref double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+
+            ldlt.smatrixldlt(ref a, n, isupper, ref pivots);
+            result = smatrixldltsolve(ref a, ref pivots, b, n, isupper, ref x);
+            return result;
+        }
+
+
+        public static bool solvesystemldlt(ref double[,] a,
+            ref int[] pivots,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int kp = 0;
+            int km1 = 0;
+            int km2 = 0;
+            int kp1 = 0;
+            int kp2 = 0;
+            double ak = 0;
+            double akm1 = 0;
+            double akm1k = 0;
+            double bk = 0;
+            double bkm1 = 0;
+            double denom = 0;
+            double v = 0;
+            int i_ = 0;
+
+            b = (double[])b.Clone();
+
+            
+            //
+            // Quick return if possible
+            //
+            result = true;
+            if( n==0 )
+            {
+                return result;
+            }
+            
+            //
+            // Check that the diagonal matrix D is nonsingular
+            //
+            if( isupper )
+            {
+                
+                //
+                // Upper triangular storage: examine D from bottom to top
+                //
+                for(i=n; i>=1; i--)
+                {
+                    if( pivots[i]>0 & (double)(a[i,i])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Lower triangular storage: examine D from top to bottom.
+                //
+                for(i=1; i<=n; i++)
+                {
+                    if( pivots[i]>0 & (double)(a[i,i])==(double)(0) )
+                    {
+                        result = false;
+                        return result;
+                    }
+                }
+            }
+            
+            //
+            // Solve Ax = b
+            //
+            if( isupper )
+            {
+                
+                //
+                // Solve A*X = B, where A = U*D*U'.
+                //
+                // First solve U*D*X = B, overwriting B with X.
+                //
+                // K is the main loop index, decreasing from N to 1 in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = n;
+                while( k>=1 )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Interchange rows K and IPIV(K).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(U(K)), where U(K) is the transformation
+                        // stored in column K of A.
+                        //
+                        km1 = k-1;
+                        v = b[k];
+                        for(i_=1; i_<=km1;i_++)
+                        {
+                            b[i_] = b[i_] - v*a[i_,k];
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        b[k] = b[k]/a[k,k];
+                        k = k-1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Interchange rows K-1 and -IPIV(K).
+                        //
+                        kp = -pivots[k];
+                        if( kp!=k-1 )
+                        {
+                            v = b[k-1];
+                            b[k-1] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(U(K)), where U(K) is the transformation
+                        // stored in columns K-1 and K of A.
+                        //
+                        km2 = k-2;
+                        km1 = k-1;
+                        v = b[k];
+                        for(i_=1; i_<=km2;i_++)
+                        {
+                            b[i_] = b[i_] - v*a[i_,k];
+                        }
+                        v = b[k-1];
+                        for(i_=1; i_<=km2;i_++)
+                        {
+                            b[i_] = b[i_] - v*a[i_,km1];
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        akm1k = a[k-1,k];
+                        akm1 = a[k-1,k-1]/akm1k;
+                        ak = a[k,k]/akm1k;
+                        denom = akm1*ak-1;
+                        bkm1 = b[k-1]/akm1k;
+                        bk = b[k]/akm1k;
+                        b[k-1] = (ak*bkm1-bk)/denom;
+                        b[k] = (akm1*bk-bkm1)/denom;
+                        k = k-2;
+                    }
+                }
+                
+                //
+                // Next solve U'*X = B, overwriting B with X.
+                //
+                // K is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = 1;
+                while( k<=n )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Multiply by inv(U'(K)), where U(K) is the transformation
+                        // stored in column K of A.
+                        //
+                        km1 = k-1;
+                        v = 0.0;
+                        for(i_=1; i_<=km1;i_++)
+                        {
+                            v += b[i_]*a[i_,k];
+                        }
+                        b[k] = b[k]-v;
+                        
+                        //
+                        // Interchange rows K and IPIV(K).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k+1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Multiply by inv(U'(K+1)), where U(K+1) is the transformation
+                        // stored in columns K and K+1 of A.
+                        //
+                        km1 = k-1;
+                        kp1 = k+1;
+                        v = 0.0;
+                        for(i_=1; i_<=km1;i_++)
+                        {
+                            v += b[i_]*a[i_,k];
+                        }
+                        b[k] = b[k]-v;
+                        v = 0.0;
+                        for(i_=1; i_<=km1;i_++)
+                        {
+                            v += b[i_]*a[i_,kp1];
+                        }
+                        b[k+1] = b[k+1]-v;
+                        
+                        //
+                        // Interchange rows K and -IPIV(K).
+                        //
+                        kp = -pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k+2;
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Solve A*X = B, where A = L*D*L'.
+                //
+                // First solve L*D*X = B, overwriting B with X.
+                //
+                // K is the main loop index, increasing from 1 to N in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = 1;
+                while( k<=n )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Interchange rows K and IPIV(K).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(L(K)), where L(K) is the transformation
+                        // stored in column K of A.
+                        //
+                        if( k<n )
+                        {
+                            kp1 = k+1;
+                            v = b[k];
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                b[i_] = b[i_] - v*a[i_,k];
+                            }
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        b[k] = b[k]/a[k,k];
+                        k = k+1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Interchange rows K+1 and -IPIV(K).
+                        //
+                        kp = -pivots[k];
+                        if( kp!=k+1 )
+                        {
+                            v = b[k+1];
+                            b[k+1] = b[kp];
+                            b[kp] = v;
+                        }
+                        
+                        //
+                        // Multiply by inv(L(K)), where L(K) is the transformation
+                        // stored in columns K and K+1 of A.
+                        //
+                        if( k<n-1 )
+                        {
+                            kp1 = k+1;
+                            kp2 = k+2;
+                            v = b[k];
+                            for(i_=kp2; i_<=n;i_++)
+                            {
+                                b[i_] = b[i_] - v*a[i_,k];
+                            }
+                            v = b[k+1];
+                            for(i_=kp2; i_<=n;i_++)
+                            {
+                                b[i_] = b[i_] - v*a[i_,kp1];
+                            }
+                        }
+                        
+                        //
+                        // Multiply by the inverse of the diagonal block.
+                        //
+                        akm1k = a[k+1,k];
+                        akm1 = a[k,k]/akm1k;
+                        ak = a[k+1,k+1]/akm1k;
+                        denom = akm1*ak-1;
+                        bkm1 = b[k]/akm1k;
+                        bk = b[k+1]/akm1k;
+                        b[k] = (ak*bkm1-bk)/denom;
+                        b[k+1] = (akm1*bk-bkm1)/denom;
+                        k = k+2;
+                    }
+                }
+                
+                //
+                // Next solve L'*X = B, overwriting B with X.
+                //
+                // K is the main loop index, decreasing from N to 1 in steps of
+                // 1 or 2, depending on the size of the diagonal blocks.
+                //
+                k = n;
+                while( k>=1 )
+                {
+                    if( pivots[k]>0 )
+                    {
+                        
+                        //
+                        // 1 x 1 diagonal block
+                        //
+                        // Multiply by inv(L'(K)), where L(K) is the transformation
+                        // stored in column K of A.
+                        //
+                        if( k<n )
+                        {
+                            kp1 = k+1;
+                            v = 0.0;
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                v += b[i_]*a[i_,k];
+                            }
+                            b[k] = b[k]-v;
+                        }
+                        
+                        //
+                        // Interchange rows K and IPIV(K).
+                        //
+                        kp = pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k-1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // 2 x 2 diagonal block
+                        //
+                        // Multiply by inv(L'(K-1)), where L(K-1) is the transformation
+                        // stored in columns K-1 and K of A.
+                        //
+                        if( k<n )
+                        {
+                            kp1 = k+1;
+                            km1 = k-1;
+                            v = 0.0;
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                v += b[i_]*a[i_,k];
+                            }
+                            b[k] = b[k]-v;
+                            v = 0.0;
+                            for(i_=kp1; i_<=n;i_++)
+                            {
+                                v += b[i_]*a[i_,km1];
+                            }
+                            b[k-1] = b[k-1]-v;
+                        }
+                        
+                        //
+                        // Interchange rows K and -IPIV(K).
+                        //
+                        kp = -pivots[k];
+                        if( kp!=k )
+                        {
+                            v = b[k];
+                            b[k] = b[kp];
+                            b[kp] = v;
+                        }
+                        k = k-2;
+                    }
+                }
+            }
+            x = new double[n+1];
+            for(i_=1; i_<=n;i_++)
+            {
+                x[i_] = b[i_];
+            }
+            return result;
+        }
+
+
+        public static bool solvesymmetricsystem(double[,] a,
+            double[] b,
+            int n,
+            bool isupper,
+            ref double[] x)
+        {
+            bool result = new bool();
+            int[] pivots = new int[0];
+
+            a = (double[,])a.Clone();
+            b = (double[])b.Clone();
+
+            ldlt.ldltdecomposition(ref a, n, isupper, ref pivots);
+            result = solvesystemldlt(ref a, ref pivots, b, n, isupper, ref x);
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/stest.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/stest.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/stest.cs	(revision 2645)
@@ -0,0 +1,121 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class stest
+    {
+        /*************************************************************************
+        Sign test
+
+        This test checks three hypotheses about the median of  the  given  sample.
+        The following tests are performed:
+            * two-tailed test (null hypothesis - the median is equal to the  given
+              value)
+            * left-tailed test (null hypothesis - the median is  greater  than  or
+              equal to the given value)
+            * right-tailed test (null hypothesis - the  median  is  less  than  or
+              equal to the given value)
+
+        Requirements:
+            * the scale of measurement should be ordinal, interval or ratio  (i.e.
+              the test could not be applied to nominal variables).
+
+        The test is non-parametric and doesn't require distribution X to be normal
+
+        Input parameters:
+            X       -   sample. Array whose index goes from 0 to N-1.
+            N       -   size of the sample.
+            Median  -   assumed median value.
+
+        Output parameters:
+            BothTails   -   p-value for two-tailed test.
+                            If BothTails is less than the given significance level
+                            the null hypothesis is rejected.
+            LeftTail    -   p-value for left-tailed test.
+                            If LeftTail is less than the given significance level,
+                            the null hypothesis is rejected.
+            RightTail   -   p-value for right-tailed test.
+                            If RightTail is less than the given significance level
+                            the null hypothesis is rejected.
+
+        While   calculating   p-values   high-precision   binomial    distribution
+        approximation is used, so significance levels have about 15 exact digits.
+
+          -- ALGLIB --
+             Copyright 08.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void onesamplesigntest(ref double[] x,
+            int n,
+            double median,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            int gtcnt = 0;
+            int necnt = 0;
+
+            if( n<=1 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Calculate:
+            // GTCnt - count of x[i]>Median
+            // NECnt - count of x[i]<>Median
+            //
+            gtcnt = 0;
+            necnt = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(x[i])>(double)(median) )
+                {
+                    gtcnt = gtcnt+1;
+                }
+                if( (double)(x[i])!=(double)(median) )
+                {
+                    necnt = necnt+1;
+                }
+            }
+            if( necnt==0 )
+            {
+                
+                //
+                // all x[i] are equal to Median.
+                // So we can conclude that Median is a true median :)
+                //
+                bothtails = 0.0;
+                lefttail = 0.0;
+                righttail = 0.0;
+                return;
+            }
+            bothtails = 2*binomialdistr.binomialdistribution(Math.Min(gtcnt, necnt-gtcnt), necnt, 0.5);
+            lefttail = binomialdistr.binomialdistribution(gtcnt, necnt, 0.5);
+            righttail = binomialdistr.binomialcdistribution(gtcnt-1, necnt, 0.5);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/studenttdistr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/studenttdistr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/studenttdistr.cs	(revision 2645)
@@ -0,0 +1,214 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class studenttdistr
+    {
+        /*************************************************************************
+        Student's t distribution
+
+        Computes the integral from minus infinity to t of the Student
+        t distribution with integer k > 0 degrees of freedom:
+
+                                             t
+                                             -
+                                            | |
+                     -                      |         2   -(k+1)/2
+                    | ( (k+1)/2 )           |  (     x   )
+              ----------------------        |  ( 1 + --- )        dx
+                            -               |  (      k  )
+              sqrt( k pi ) | ( k/2 )        |
+                                          | |
+                                           -
+                                          -inf.
+
+        Relation to incomplete beta integral:
+
+               1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z )
+        where
+               z = k/(k + t**2).
+
+        For t < -2, this is the method of computation.  For higher t,
+        a direct method is derived from integration by parts.
+        Since the function is symmetric about t=0, the area under the
+        right tail of the density is found by calling the function
+        with -t instead of t.
+
+        ACCURACY:
+
+        Tested at random 1 <= k <= 25.  The "domain" refers to t.
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE     -100,-2      50000       5.9e-15     1.4e-15
+           IEEE     -2,100      500000       2.7e-15     4.9e-17
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double studenttdistribution(int k,
+            double t)
+        {
+            double result = 0;
+            double x = 0;
+            double rk = 0;
+            double z = 0;
+            double f = 0;
+            double tz = 0;
+            double p = 0;
+            double xsqk = 0;
+            int j = 0;
+
+            System.Diagnostics.Debug.Assert(k>0, "Domain error in StudentTDistribution");
+            if( (double)(t)==(double)(0) )
+            {
+                result = 0.5;
+                return result;
+            }
+            if( (double)(t)<(double)(-2.0) )
+            {
+                rk = k;
+                z = rk/(rk+t*t);
+                result = 0.5*ibetaf.incompletebeta(0.5*rk, 0.5, z);
+                return result;
+            }
+            if( (double)(t)<(double)(0) )
+            {
+                x = -t;
+            }
+            else
+            {
+                x = t;
+            }
+            rk = k;
+            z = 1.0+x*x/rk;
+            if( k%2!=0 )
+            {
+                xsqk = x/Math.Sqrt(rk);
+                p = Math.Atan(xsqk);
+                if( k>1 )
+                {
+                    f = 1.0;
+                    tz = 1.0;
+                    j = 3;
+                    while( j<=k-2 & (double)(tz/f)>(double)(AP.Math.MachineEpsilon) )
+                    {
+                        tz = tz*((j-1)/(z*j));
+                        f = f+tz;
+                        j = j+2;
+                    }
+                    p = p+f*xsqk/z;
+                }
+                p = p*2.0/Math.PI;
+            }
+            else
+            {
+                f = 1.0;
+                tz = 1.0;
+                j = 2;
+                while( j<=k-2 & (double)(tz/f)>(double)(AP.Math.MachineEpsilon) )
+                {
+                    tz = tz*((j-1)/(z*j));
+                    f = f+tz;
+                    j = j+2;
+                }
+                p = f*x/Math.Sqrt(z*rk);
+            }
+            if( (double)(t)<(double)(0) )
+            {
+                p = -p;
+            }
+            result = 0.5+0.5*p;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Functional inverse of Student's t distribution
+
+        Given probability p, finds the argument t such that stdtr(k,t)
+        is equal to p.
+
+        ACCURACY:
+
+        Tested at random 1 <= k <= 100.  The "domain" refers to p:
+                             Relative error:
+        arithmetic   domain     # trials      peak         rms
+           IEEE    .001,.999     25000       5.7e-15     8.0e-16
+           IEEE    10^-6,.001    25000       2.0e-12     2.9e-14
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static double invstudenttdistribution(int k,
+            double p)
+        {
+            double result = 0;
+            double t = 0;
+            double rk = 0;
+            double z = 0;
+            int rflg = 0;
+
+            System.Diagnostics.Debug.Assert(k>0 & (double)(p)>(double)(0) & (double)(p)<(double)(1), "Domain error in InvStudentTDistribution");
+            rk = k;
+            if( (double)(p)>(double)(0.25) & (double)(p)<(double)(0.75) )
+            {
+                if( (double)(p)==(double)(0.5) )
+                {
+                    result = 0;
+                    return result;
+                }
+                z = 1.0-2.0*p;
+                z = ibetaf.invincompletebeta(0.5, 0.5*rk, Math.Abs(z));
+                t = Math.Sqrt(rk*z/(1.0-z));
+                if( (double)(p)<(double)(0.5) )
+                {
+                    t = -t;
+                }
+                result = t;
+                return result;
+            }
+            rflg = -1;
+            if( (double)(p)>=(double)(0.5) )
+            {
+                p = 1.0-p;
+                rflg = 1;
+            }
+            z = ibetaf.invincompletebeta(0.5*rk, 0.5, 2.0*p);
+            if( (double)(AP.Math.MaxRealNumber*z)<(double)(rk) )
+            {
+                result = rflg*AP.Math.MaxRealNumber;
+                return result;
+            }
+            t = Math.Sqrt(rk/z-rk);
+            result = rflg*t;
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/studentttests.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/studentttests.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/studentttests.cs	(revision 2645)
@@ -0,0 +1,367 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class studentttests
+    {
+        /*************************************************************************
+        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.
+
+          -- ALGLIB --
+             Copyright 08.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void studentttest1(ref double[] x,
+            int n,
+            double mean,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            double xmean = 0;
+            double xvariance = 0;
+            double xstddev = 0;
+            double v1 = 0;
+            double v2 = 0;
+            double stat = 0;
+            double s = 0;
+
+            if( n<=1 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            xmean = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xmean = xmean+x[i];
+            }
+            xmean = xmean/n;
+            
+            //
+            // Variance (using corrected two-pass algorithm)
+            //
+            xvariance = 0;
+            xstddev = 0;
+            if( n!=1 )
+            {
+                v1 = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v1 = v1+AP.Math.Sqr(x[i]-xmean);
+                }
+                v2 = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v2 = v2+(x[i]-xmean);
+                }
+                v2 = AP.Math.Sqr(v2)/n;
+                xvariance = (v1-v2)/(n-1);
+                if( (double)(xvariance)<(double)(0) )
+                {
+                    xvariance = 0;
+                }
+                xstddev = Math.Sqrt(xvariance);
+            }
+            if( (double)(xstddev)==(double)(0) )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Statistic
+            //
+            stat = (xmean-mean)/(xstddev/Math.Sqrt(n));
+            s = studenttdistr.studenttdistribution(n-1, stat);
+            bothtails = 2*Math.Min(s, 1-s);
+            lefttail = s;
+            righttail = 1-s;
+        }
+
+
+        /*************************************************************************
+        Two-sample pooled test
+
+        This test checks three hypotheses about the mean of the given samples. The
+        following tests are performed:
+            * two-tailed test (null hypothesis - the means are equal)
+            * left-tailed test (null hypothesis - the mean of the first sample  is
+              greater than or equal to the mean of the second sample)
+            * right-tailed test (null hypothesis - the mean of the first sample is
+              less than or equal to the mean of the second sample).
+
+        Test is based on the following assumptions:
+            * given samples have normal distributions
+            * dispersions are equal
+            * samples are independent.
+
+        Input parameters:
+            X       -   sample 1. Array whose index goes from 0 to N-1.
+            N       -   size of sample.
+            Y       -   sample 2. Array whose index goes from 0 to M-1.
+            M       -   size of sample.
+
+        Output parameters:
+            BothTails   -   p-value for two-tailed test.
+                            If BothTails is less than the given significance level
+                            the null hypothesis is rejected.
+            LeftTail    -   p-value for left-tailed test.
+                            If LeftTail is less than the given significance level,
+                            the null hypothesis is rejected.
+            RightTail   -   p-value for right-tailed test.
+                            If RightTail is less than the given significance level
+                            the null hypothesis is rejected.
+
+          -- ALGLIB --
+             Copyright 18.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void studentttest2(ref double[] x,
+            int n,
+            ref double[] y,
+            int m,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            double xmean = 0;
+            double ymean = 0;
+            double stat = 0;
+            double s = 0;
+            double p = 0;
+
+            if( n<=1 | m<=1 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            xmean = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xmean = xmean+x[i];
+            }
+            xmean = xmean/n;
+            ymean = 0;
+            for(i=0; i<=m-1; i++)
+            {
+                ymean = ymean+y[i];
+            }
+            ymean = ymean/m;
+            
+            //
+            // S
+            //
+            s = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                s = s+AP.Math.Sqr(x[i]-xmean);
+            }
+            for(i=0; i<=m-1; i++)
+            {
+                s = s+AP.Math.Sqr(y[i]-ymean);
+            }
+            s = Math.Sqrt(s*((double)(1)/(double)(n)+(double)(1)/(double)(m))/(n+m-2));
+            if( (double)(s)==(double)(0) )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Statistic
+            //
+            stat = (xmean-ymean)/s;
+            p = studenttdistr.studenttdistribution(n+m-2, stat);
+            bothtails = 2*Math.Min(p, 1-p);
+            lefttail = p;
+            righttail = 1-p;
+        }
+
+
+        /*************************************************************************
+        Two-sample unpooled test
+
+        This test checks three hypotheses about the mean of the given samples. The
+        following tests are performed:
+            * two-tailed test (null hypothesis - the means are equal)
+            * left-tailed test (null hypothesis - the mean of the first sample  is
+              greater than or equal to the mean of the second sample)
+            * right-tailed test (null hypothesis - the mean of the first sample is
+              less than or equal to the mean of the second sample).
+
+        Test is based on the following assumptions:
+            * given samples have normal distributions
+            * samples are independent.
+        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.
+
+          -- ALGLIB --
+             Copyright 18.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void unequalvariancettest(ref double[] x,
+            int n,
+            ref double[] y,
+            int m,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            double xmean = 0;
+            double ymean = 0;
+            double xvar = 0;
+            double yvar = 0;
+            double df = 0;
+            double p = 0;
+            double stat = 0;
+            double c = 0;
+
+            if( n<=1 | m<=1 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            xmean = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xmean = xmean+x[i];
+            }
+            xmean = xmean/n;
+            ymean = 0;
+            for(i=0; i<=m-1; i++)
+            {
+                ymean = ymean+y[i];
+            }
+            ymean = ymean/m;
+            
+            //
+            // Variance (using corrected two-pass algorithm)
+            //
+            xvar = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xvar = xvar+AP.Math.Sqr(x[i]-xmean);
+            }
+            xvar = xvar/(n-1);
+            yvar = 0;
+            for(i=0; i<=m-1; i++)
+            {
+                yvar = yvar+AP.Math.Sqr(y[i]-ymean);
+            }
+            yvar = yvar/(m-1);
+            if( (double)(xvar)==(double)(0) | (double)(yvar)==(double)(0) )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Statistic
+            //
+            stat = (xmean-ymean)/Math.Sqrt(xvar/n+yvar/m);
+            c = xvar/n/(xvar/n+yvar/m);
+            df = (n-1)*(m-1)/((m-1)*AP.Math.Sqr(c)+(n-1)*(1-AP.Math.Sqr(c)));
+            if( (double)(stat)>(double)(0) )
+            {
+                p = 1-0.5*ibetaf.incompletebeta(df/2, 0.5, df/(df+AP.Math.Sqr(stat)));
+            }
+            else
+            {
+                p = 0.5*ibetaf.incompletebeta(df/2, 0.5, df/(df+AP.Math.Sqr(stat)));
+            }
+            bothtails = 2*Math.Min(p, 1-p);
+            lefttail = p;
+            righttail = 1-p;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/svd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/svd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/svd.cs	(revision 2645)
@@ -0,0 +1,606 @@
+/*************************************************************************
+Copyright (c) 2005-2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class svd
+    {
+        /*************************************************************************
+        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 doesnt use additional
+                               memory (lower requirements, lower performance).
+                             * equals 1, the algorithm uses additional
+                               memory of size min(M,N)*min(M,N) of real numbers.
+                               It often speeds up the algorithm.
+                             * equals 2, the algorithm uses additional
+                               memory of size M*min(M,N) of real numbers.
+                               It allows to get a maximum performance.
+                            The recommended value of the parameter is 2.
+
+        Output parameters:
+            W           -   contains singular values in descending order.
+            U           -   if UNeeded=0, U isn't changed, the left singular vectors
+                            are not calculated.
+                            if Uneeded=1, U contains left singular vectors (first
+                            min(M,N) columns of matrix U). Array whose indexes range
+                            within [0..M-1, 0..Min(M,N)-1].
+                            if UNeeded=2, U contains matrix U wholly. Array whose
+                            indexes range within [0..M-1, 0..M-1].
+            VT          -   if VTNeeded=0, VT isnt changed, the right singular vectors
+                            are not calculated.
+                            if VTNeeded=1, VT contains right singular vectors (first
+                            min(M,N) rows of matrix V^T). Array whose indexes range
+                            within [0..min(M,N)-1, 0..N-1].
+                            if VTNeeded=2, VT contains matrix V^T wholly. Array whose
+                            indexes range within [0..N-1, 0..N-1].
+
+          -- ALGLIB --
+             Copyright 2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool rmatrixsvd(double[,] a,
+            int m,
+            int n,
+            int uneeded,
+            int vtneeded,
+            int additionalmemory,
+            ref double[] w,
+            ref double[,] u,
+            ref double[,] vt)
+        {
+            bool result = new bool();
+            double[] tauq = new double[0];
+            double[] taup = new double[0];
+            double[] tau = new double[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            double[,] t2 = new double[0,0];
+            bool isupper = new bool();
+            int minmn = 0;
+            int ncu = 0;
+            int nrvt = 0;
+            int nru = 0;
+            int ncvt = 0;
+            int i = 0;
+            int j = 0;
+            int im1 = 0;
+            double sm = 0;
+
+            a = (double[,])a.Clone();
+
+            result = true;
+            if( m==0 | n==0 )
+            {
+                return result;
+            }
+            System.Diagnostics.Debug.Assert(uneeded>=0 & uneeded<=2, "SVDDecomposition: wrong parameters!");
+            System.Diagnostics.Debug.Assert(vtneeded>=0 & vtneeded<=2, "SVDDecomposition: wrong parameters!");
+            System.Diagnostics.Debug.Assert(additionalmemory>=0 & additionalmemory<=2, "SVDDecomposition: wrong parameters!");
+            
+            //
+            // initialize
+            //
+            minmn = Math.Min(m, n);
+            w = new double[minmn+1];
+            ncu = 0;
+            nru = 0;
+            if( uneeded==1 )
+            {
+                nru = m;
+                ncu = minmn;
+                u = new double[nru-1+1, ncu-1+1];
+            }
+            if( uneeded==2 )
+            {
+                nru = m;
+                ncu = m;
+                u = new double[nru-1+1, ncu-1+1];
+            }
+            nrvt = 0;
+            ncvt = 0;
+            if( vtneeded==1 )
+            {
+                nrvt = minmn;
+                ncvt = n;
+                vt = new double[nrvt-1+1, ncvt-1+1];
+            }
+            if( vtneeded==2 )
+            {
+                nrvt = n;
+                ncvt = n;
+                vt = new double[nrvt-1+1, ncvt-1+1];
+            }
+            
+            //
+            // M much larger than N
+            // Use bidiagonal reduction with QR-decomposition
+            //
+            if( (double)(m)>(double)(1.6*n) )
+            {
+                if( uneeded==0 )
+                {
+                    
+                    //
+                    // No left singular vectors to be computed
+                    //
+                    qr.rmatrixqr(ref a, m, n, ref tau);
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(j=0; j<=i-1; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.rmatrixbd(ref a, n, n, ref tauq, ref taup);
+                    bidiagonal.rmatrixbdunpackpt(ref a, n, n, ref taup, nrvt, ref vt);
+                    bidiagonal.rmatrixbdunpackdiagonals(ref a, n, n, ref isupper, ref w, ref e);
+                    result = bdsvd.rmatrixbdsvd(ref w, e, n, isupper, false, ref u, 0, ref a, 0, ref vt, ncvt);
+                    return result;
+                }
+                else
+                {
+                    
+                    //
+                    // Left singular vectors (may be full matrix U) to be computed
+                    //
+                    qr.rmatrixqr(ref a, m, n, ref tau);
+                    qr.rmatrixqrunpackq(ref a, m, n, ref tau, ncu, ref u);
+                    for(i=0; i<=n-1; i++)
+                    {
+                        for(j=0; j<=i-1; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.rmatrixbd(ref a, n, n, ref tauq, ref taup);
+                    bidiagonal.rmatrixbdunpackpt(ref a, n, n, ref taup, nrvt, ref vt);
+                    bidiagonal.rmatrixbdunpackdiagonals(ref a, n, n, ref isupper, ref w, ref e);
+                    if( additionalmemory<1 )
+                    {
+                        
+                        //
+                        // No additional memory can be used
+                        //
+                        bidiagonal.rmatrixbdmultiplybyq(ref a, n, n, ref tauq, ref u, m, n, true, false);
+                        result = bdsvd.rmatrixbdsvd(ref w, e, n, isupper, false, ref u, m, ref a, 0, ref vt, ncvt);
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Large U. Transforming intermediate matrix T2
+                        //
+                        work = new double[Math.Max(m, n)+1];
+                        bidiagonal.rmatrixbdunpackq(ref a, n, n, ref tauq, n, ref t2);
+                        blas.copymatrix(ref u, 0, m-1, 0, n-1, ref a, 0, m-1, 0, n-1);
+                        blas.inplacetranspose(ref t2, 0, n-1, 0, n-1, ref work);
+                        result = bdsvd.rmatrixbdsvd(ref w, e, n, isupper, false, ref u, 0, ref t2, n, ref vt, ncvt);
+                        blas.matrixmatrixmultiply(ref a, 0, m-1, 0, n-1, false, ref t2, 0, n-1, 0, n-1, true, 1.0, ref u, 0, m-1, 0, n-1, 0.0, ref work);
+                    }
+                    return result;
+                }
+            }
+            
+            //
+            // N much larger than M
+            // Use bidiagonal reduction with LQ-decomposition
+            //
+            if( (double)(n)>(double)(1.6*m) )
+            {
+                if( vtneeded==0 )
+                {
+                    
+                    //
+                    // No right singular vectors to be computed
+                    //
+                    lq.rmatrixlq(ref a, m, n, ref tau);
+                    for(i=0; i<=m-1; i++)
+                    {
+                        for(j=i+1; j<=m-1; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.rmatrixbd(ref a, m, m, ref tauq, ref taup);
+                    bidiagonal.rmatrixbdunpackq(ref a, m, m, ref tauq, ncu, ref u);
+                    bidiagonal.rmatrixbdunpackdiagonals(ref a, m, m, ref isupper, ref w, ref e);
+                    work = new double[m+1];
+                    blas.inplacetranspose(ref u, 0, nru-1, 0, ncu-1, ref work);
+                    result = bdsvd.rmatrixbdsvd(ref w, e, m, isupper, false, ref a, 0, ref u, nru, ref vt, 0);
+                    blas.inplacetranspose(ref u, 0, nru-1, 0, ncu-1, ref work);
+                    return result;
+                }
+                else
+                {
+                    
+                    //
+                    // Right singular vectors (may be full matrix VT) to be computed
+                    //
+                    lq.rmatrixlq(ref a, m, n, ref tau);
+                    lq.rmatrixlqunpackq(ref a, m, n, ref tau, nrvt, ref vt);
+                    for(i=0; i<=m-1; i++)
+                    {
+                        for(j=i+1; j<=m-1; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.rmatrixbd(ref a, m, m, ref tauq, ref taup);
+                    bidiagonal.rmatrixbdunpackq(ref a, m, m, ref tauq, ncu, ref u);
+                    bidiagonal.rmatrixbdunpackdiagonals(ref a, m, m, ref isupper, ref w, ref e);
+                    work = new double[Math.Max(m, n)+1];
+                    blas.inplacetranspose(ref u, 0, nru-1, 0, ncu-1, ref work);
+                    if( additionalmemory<1 )
+                    {
+                        
+                        //
+                        // No additional memory available
+                        //
+                        bidiagonal.rmatrixbdmultiplybyp(ref a, m, m, ref taup, ref vt, m, n, false, true);
+                        result = bdsvd.rmatrixbdsvd(ref w, e, m, isupper, false, ref a, 0, ref u, nru, ref vt, n);
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Large VT. Transforming intermediate matrix T2
+                        //
+                        bidiagonal.rmatrixbdunpackpt(ref a, m, m, ref taup, m, ref t2);
+                        result = bdsvd.rmatrixbdsvd(ref w, e, m, isupper, false, ref a, 0, ref u, nru, ref t2, m);
+                        blas.copymatrix(ref vt, 0, m-1, 0, n-1, ref a, 0, m-1, 0, n-1);
+                        blas.matrixmatrixmultiply(ref t2, 0, m-1, 0, m-1, false, ref a, 0, m-1, 0, n-1, false, 1.0, ref vt, 0, m-1, 0, n-1, 0.0, ref work);
+                    }
+                    blas.inplacetranspose(ref u, 0, nru-1, 0, ncu-1, ref work);
+                    return result;
+                }
+            }
+            
+            //
+            // M<=N
+            // We can use inplace transposition of U to get rid of columnwise operations
+            //
+            if( m<=n )
+            {
+                bidiagonal.rmatrixbd(ref a, m, n, ref tauq, ref taup);
+                bidiagonal.rmatrixbdunpackq(ref a, m, n, ref tauq, ncu, ref u);
+                bidiagonal.rmatrixbdunpackpt(ref a, m, n, ref taup, nrvt, ref vt);
+                bidiagonal.rmatrixbdunpackdiagonals(ref a, m, n, ref isupper, ref w, ref e);
+                work = new double[m+1];
+                blas.inplacetranspose(ref u, 0, nru-1, 0, ncu-1, ref work);
+                result = bdsvd.rmatrixbdsvd(ref w, e, minmn, isupper, false, ref a, 0, ref u, nru, ref vt, ncvt);
+                blas.inplacetranspose(ref u, 0, nru-1, 0, ncu-1, ref work);
+                return result;
+            }
+            
+            //
+            // Simple bidiagonal reduction
+            //
+            bidiagonal.rmatrixbd(ref a, m, n, ref tauq, ref taup);
+            bidiagonal.rmatrixbdunpackq(ref a, m, n, ref tauq, ncu, ref u);
+            bidiagonal.rmatrixbdunpackpt(ref a, m, n, ref taup, nrvt, ref vt);
+            bidiagonal.rmatrixbdunpackdiagonals(ref a, m, n, ref isupper, ref w, ref e);
+            if( additionalmemory<2 | uneeded==0 )
+            {
+                
+                //
+                // We cant use additional memory or there is no need in such operations
+                //
+                result = bdsvd.rmatrixbdsvd(ref w, e, minmn, isupper, false, ref u, nru, ref a, 0, ref vt, ncvt);
+            }
+            else
+            {
+                
+                //
+                // We can use additional memory
+                //
+                t2 = new double[minmn-1+1, m-1+1];
+                blas.copyandtranspose(ref u, 0, m-1, 0, minmn-1, ref t2, 0, minmn-1, 0, m-1);
+                result = bdsvd.rmatrixbdsvd(ref w, e, minmn, isupper, false, ref u, 0, ref t2, m, ref vt, ncvt);
+                blas.copyandtranspose(ref t2, 0, minmn-1, 0, m-1, ref u, 0, m-1, 0, minmn-1);
+            }
+            return result;
+        }
+
+
+        public static bool svddecomposition(double[,] a,
+            int m,
+            int n,
+            int uneeded,
+            int vtneeded,
+            int additionalmemory,
+            ref double[] w,
+            ref double[,] u,
+            ref double[,] vt)
+        {
+            bool result = new bool();
+            double[] tauq = new double[0];
+            double[] taup = new double[0];
+            double[] tau = new double[0];
+            double[] e = new double[0];
+            double[] work = new double[0];
+            double[,] t2 = new double[0,0];
+            bool isupper = new bool();
+            int minmn = 0;
+            int ncu = 0;
+            int nrvt = 0;
+            int nru = 0;
+            int ncvt = 0;
+            int i = 0;
+            int j = 0;
+            int im1 = 0;
+            double sm = 0;
+
+            a = (double[,])a.Clone();
+
+            result = true;
+            if( m==0 | n==0 )
+            {
+                return result;
+            }
+            System.Diagnostics.Debug.Assert(uneeded>=0 & uneeded<=2, "SVDDecomposition: wrong parameters!");
+            System.Diagnostics.Debug.Assert(vtneeded>=0 & vtneeded<=2, "SVDDecomposition: wrong parameters!");
+            System.Diagnostics.Debug.Assert(additionalmemory>=0 & additionalmemory<=2, "SVDDecomposition: wrong parameters!");
+            
+            //
+            // initialize
+            //
+            minmn = Math.Min(m, n);
+            w = new double[minmn+1];
+            ncu = 0;
+            nru = 0;
+            if( uneeded==1 )
+            {
+                nru = m;
+                ncu = minmn;
+                u = new double[nru+1, ncu+1];
+            }
+            if( uneeded==2 )
+            {
+                nru = m;
+                ncu = m;
+                u = new double[nru+1, ncu+1];
+            }
+            nrvt = 0;
+            ncvt = 0;
+            if( vtneeded==1 )
+            {
+                nrvt = minmn;
+                ncvt = n;
+                vt = new double[nrvt+1, ncvt+1];
+            }
+            if( vtneeded==2 )
+            {
+                nrvt = n;
+                ncvt = n;
+                vt = new double[nrvt+1, ncvt+1];
+            }
+            
+            //
+            // M much larger than N
+            // Use bidiagonal reduction with QR-decomposition
+            //
+            if( (double)(m)>(double)(1.6*n) )
+            {
+                if( uneeded==0 )
+                {
+                    
+                    //
+                    // No left singular vectors to be computed
+                    //
+                    qr.qrdecomposition(ref a, m, n, ref tau);
+                    for(i=2; i<=n; i++)
+                    {
+                        for(j=1; j<=i-1; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.tobidiagonal(ref a, n, n, ref tauq, ref taup);
+                    bidiagonal.unpackptfrombidiagonal(ref a, n, n, ref taup, nrvt, ref vt);
+                    bidiagonal.unpackdiagonalsfrombidiagonal(ref a, n, n, ref isupper, ref w, ref e);
+                    result = bdsvd.bidiagonalsvddecomposition(ref w, e, n, isupper, false, ref u, 0, ref a, 0, ref vt, ncvt);
+                    return result;
+                }
+                else
+                {
+                    
+                    //
+                    // Left singular vectors (may be full matrix U) to be computed
+                    //
+                    qr.qrdecomposition(ref a, m, n, ref tau);
+                    qr.unpackqfromqr(ref a, m, n, ref tau, ncu, ref u);
+                    for(i=2; i<=n; i++)
+                    {
+                        for(j=1; j<=i-1; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.tobidiagonal(ref a, n, n, ref tauq, ref taup);
+                    bidiagonal.unpackptfrombidiagonal(ref a, n, n, ref taup, nrvt, ref vt);
+                    bidiagonal.unpackdiagonalsfrombidiagonal(ref a, n, n, ref isupper, ref w, ref e);
+                    if( additionalmemory<1 )
+                    {
+                        
+                        //
+                        // No additional memory can be used
+                        //
+                        bidiagonal.multiplybyqfrombidiagonal(ref a, n, n, ref tauq, ref u, m, n, true, false);
+                        result = bdsvd.bidiagonalsvddecomposition(ref w, e, n, isupper, false, ref u, m, ref a, 0, ref vt, ncvt);
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Large U. Transforming intermediate matrix T2
+                        //
+                        work = new double[Math.Max(m, n)+1];
+                        bidiagonal.unpackqfrombidiagonal(ref a, n, n, ref tauq, n, ref t2);
+                        blas.copymatrix(ref u, 1, m, 1, n, ref a, 1, m, 1, n);
+                        blas.inplacetranspose(ref t2, 1, n, 1, n, ref work);
+                        result = bdsvd.bidiagonalsvddecomposition(ref w, e, n, isupper, false, ref u, 0, ref t2, n, ref vt, ncvt);
+                        blas.matrixmatrixmultiply(ref a, 1, m, 1, n, false, ref t2, 1, n, 1, n, true, 1.0, ref u, 1, m, 1, n, 0.0, ref work);
+                    }
+                    return result;
+                }
+            }
+            
+            //
+            // N much larger than M
+            // Use bidiagonal reduction with LQ-decomposition
+            //
+            if( (double)(n)>(double)(1.6*m) )
+            {
+                if( vtneeded==0 )
+                {
+                    
+                    //
+                    // No right singular vectors to be computed
+                    //
+                    lq.lqdecomposition(ref a, m, n, ref tau);
+                    for(i=1; i<=m-1; i++)
+                    {
+                        for(j=i+1; j<=m; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.tobidiagonal(ref a, m, m, ref tauq, ref taup);
+                    bidiagonal.unpackqfrombidiagonal(ref a, m, m, ref tauq, ncu, ref u);
+                    bidiagonal.unpackdiagonalsfrombidiagonal(ref a, m, m, ref isupper, ref w, ref e);
+                    work = new double[m+1];
+                    blas.inplacetranspose(ref u, 1, nru, 1, ncu, ref work);
+                    result = bdsvd.bidiagonalsvddecomposition(ref w, e, m, isupper, false, ref a, 0, ref u, nru, ref vt, 0);
+                    blas.inplacetranspose(ref u, 1, nru, 1, ncu, ref work);
+                    return result;
+                }
+                else
+                {
+                    
+                    //
+                    // Right singular vectors (may be full matrix VT) to be computed
+                    //
+                    lq.lqdecomposition(ref a, m, n, ref tau);
+                    lq.unpackqfromlq(ref a, m, n, ref tau, nrvt, ref vt);
+                    for(i=1; i<=m-1; i++)
+                    {
+                        for(j=i+1; j<=m; j++)
+                        {
+                            a[i,j] = 0;
+                        }
+                    }
+                    bidiagonal.tobidiagonal(ref a, m, m, ref tauq, ref taup);
+                    bidiagonal.unpackqfrombidiagonal(ref a, m, m, ref tauq, ncu, ref u);
+                    bidiagonal.unpackdiagonalsfrombidiagonal(ref a, m, m, ref isupper, ref w, ref e);
+                    work = new double[Math.Max(m, n)+1];
+                    blas.inplacetranspose(ref u, 1, nru, 1, ncu, ref work);
+                    if( additionalmemory<1 )
+                    {
+                        
+                        //
+                        // No additional memory available
+                        //
+                        bidiagonal.multiplybypfrombidiagonal(ref a, m, m, ref taup, ref vt, m, n, false, true);
+                        result = bdsvd.bidiagonalsvddecomposition(ref w, e, m, isupper, false, ref a, 0, ref u, nru, ref vt, n);
+                    }
+                    else
+                    {
+                        
+                        //
+                        // Large VT. Transforming intermediate matrix T2
+                        //
+                        bidiagonal.unpackptfrombidiagonal(ref a, m, m, ref taup, m, ref t2);
+                        result = bdsvd.bidiagonalsvddecomposition(ref w, e, m, isupper, false, ref a, 0, ref u, nru, ref t2, m);
+                        blas.copymatrix(ref vt, 1, m, 1, n, ref a, 1, m, 1, n);
+                        blas.matrixmatrixmultiply(ref t2, 1, m, 1, m, false, ref a, 1, m, 1, n, false, 1.0, ref vt, 1, m, 1, n, 0.0, ref work);
+                    }
+                    blas.inplacetranspose(ref u, 1, nru, 1, ncu, ref work);
+                    return result;
+                }
+            }
+            
+            //
+            // M<=N
+            // We can use inplace transposition of U to get rid of columnwise operations
+            //
+            if( m<=n )
+            {
+                bidiagonal.tobidiagonal(ref a, m, n, ref tauq, ref taup);
+                bidiagonal.unpackqfrombidiagonal(ref a, m, n, ref tauq, ncu, ref u);
+                bidiagonal.unpackptfrombidiagonal(ref a, m, n, ref taup, nrvt, ref vt);
+                bidiagonal.unpackdiagonalsfrombidiagonal(ref a, m, n, ref isupper, ref w, ref e);
+                work = new double[m+1];
+                blas.inplacetranspose(ref u, 1, nru, 1, ncu, ref work);
+                result = bdsvd.bidiagonalsvddecomposition(ref w, e, minmn, isupper, false, ref a, 0, ref u, nru, ref vt, ncvt);
+                blas.inplacetranspose(ref u, 1, nru, 1, ncu, ref work);
+                return result;
+            }
+            
+            //
+            // Simple bidiagonal reduction
+            //
+            bidiagonal.tobidiagonal(ref a, m, n, ref tauq, ref taup);
+            bidiagonal.unpackqfrombidiagonal(ref a, m, n, ref tauq, ncu, ref u);
+            bidiagonal.unpackptfrombidiagonal(ref a, m, n, ref taup, nrvt, ref vt);
+            bidiagonal.unpackdiagonalsfrombidiagonal(ref a, m, n, ref isupper, ref w, ref e);
+            if( additionalmemory<2 | uneeded==0 )
+            {
+                
+                //
+                // We cant use additional memory or there is no need in such operations
+                //
+                result = bdsvd.bidiagonalsvddecomposition(ref w, e, minmn, isupper, false, ref u, nru, ref a, 0, ref vt, ncvt);
+            }
+            else
+            {
+                
+                //
+                // We can use additional memory
+                //
+                t2 = new double[minmn+1, m+1];
+                blas.copyandtranspose(ref u, 1, m, 1, minmn, ref t2, 1, minmn, 1, m);
+                result = bdsvd.bidiagonalsvddecomposition(ref w, e, minmn, isupper, false, ref u, 0, ref t2, m, ref vt, ncvt);
+                blas.copyandtranspose(ref t2, 1, minmn, 1, m, ref u, 1, m, 1, minmn);
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/taskgen.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/taskgen.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/taskgen.cs	(revision 2645)
@@ -0,0 +1,201 @@
+/*************************************************************************
+Copyright (c) 2009, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class taskgen
+    {
+        /*************************************************************************
+        This  function  generates  1-dimensional  general  interpolation task with
+        moderate Lipshitz constant (close to 1.0)
+
+        If N=1 then suborutine generates only one point at the middle of [A,B]
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void taskgenint1d(double a,
+            double b,
+            int n,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            double h = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!");
+            x = new double[n];
+            y = new double[n];
+            if( n>1 )
+            {
+                x[0] = a;
+                y[0] = 2*AP.Math.RandomReal()-1;
+                h = (b-a)/(n-1);
+                for(i=1; i<=n-1; i++)
+                {
+                    if( i!=n-1 )
+                    {
+                        x[i] = a+(i+0.2*(2*AP.Math.RandomReal()-1))*h;
+                    }
+                    else
+                    {
+                        x[i] = b;
+                    }
+                    y[i] = y[i-1]+(2*AP.Math.RandomReal()-1)*(x[i]-x[i-1]);
+                }
+            }
+            else
+            {
+                x[0] = 0.5*(a+b);
+                y[0] = 2*AP.Math.RandomReal()-1;
+            }
+        }
+
+
+        /*************************************************************************
+        This function generates  1-dimensional equidistant interpolation task with
+        moderate Lipshitz constant (close to 1.0)
+
+        If N=1 then suborutine generates only one point at the middle of [A,B]
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void taskgenint1dequidist(double a,
+            double b,
+            int n,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            double h = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!");
+            x = new double[n];
+            y = new double[n];
+            if( n>1 )
+            {
+                x[0] = a;
+                y[0] = 2*AP.Math.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*AP.Math.RandomReal()-1)*h;
+                }
+            }
+            else
+            {
+                x[0] = 0.5*(a+b);
+                y[0] = 2*AP.Math.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]
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void taskgenint1dcheb1(double a,
+            double b,
+            int n,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            double h = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "TaskGenInterpolation1DCheb1: N<1!");
+            x = new double[n];
+            y = new double[n];
+            if( n>1 )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    x[i] = 0.5*(b+a)+0.5*(b-a)*Math.Cos(Math.PI*(2*i+1)/(2*n));
+                    if( i==0 )
+                    {
+                        y[i] = 2*AP.Math.RandomReal()-1;
+                    }
+                    else
+                    {
+                        y[i] = y[i-1]+(2*AP.Math.RandomReal()-1)*(x[i]-x[i-1]);
+                    }
+                }
+            }
+            else
+            {
+                x[0] = 0.5*(a+b);
+                y[0] = 2*AP.Math.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]
+
+          -- ALGLIB --
+             Copyright 02.12.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void taskgenint1dcheb2(double a,
+            double b,
+            int n,
+            ref double[] x,
+            ref double[] y)
+        {
+            int i = 0;
+            double h = 0;
+
+            System.Diagnostics.Debug.Assert(n>=1, "TaskGenInterpolation1DCheb2: N<1!");
+            x = new double[n];
+            y = new double[n];
+            if( n>1 )
+            {
+                for(i=0; i<=n-1; i++)
+                {
+                    x[i] = 0.5*(b+a)+0.5*(b-a)*Math.Cos(Math.PI*i/(n-1));
+                    if( i==0 )
+                    {
+                        y[i] = 2*AP.Math.RandomReal()-1;
+                    }
+                    else
+                    {
+                        y[i] = y[i-1]+(2*AP.Math.RandomReal()-1)*(x[i]-x[i-1]);
+                    }
+                }
+            }
+            else
+            {
+                x[0] = 0.5*(a+b);
+                y[0] = 2*AP.Math.RandomReal()-1;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tdbisinv.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tdbisinv.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tdbisinv.cs	(revision 2645)
@@ -0,0 +1,2667 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class tdbisinv
+    {
+        /*************************************************************************
+        Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a
+        given half-interval (A, B] by using bisection and inverse iteration.
+
+        Input parameters:
+            D       -   the main diagonal of a tridiagonal matrix.
+                        Array whose index ranges within [0..N-1].
+            E       -   the secondary diagonal of a tridiagonal matrix.
+                        Array whose index ranges within [0..N-2].
+            N       -   size of matrix, N>=0.
+            ZNeeded -   flag controlling whether the eigenvectors are needed or not.
+                        If ZNeeded is equal to:
+                         * 0, the eigenvectors are not needed;
+                         * 1, the eigenvectors of a tridiagonal matrix are multiplied
+                           by the square matrix Z. It is used if the tridiagonal
+                           matrix is obtained by the similarity transformation
+                           of a symmetric matrix.
+                         * 2, the eigenvectors of a tridiagonal matrix replace matrix Z.
+            A, B    -   half-interval (A, B] to search eigenvalues in.
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z isn't used and remains unchanged;
+                         * 1, Z contains the square matrix (array whose indexes range
+                           within [0..N-1, 0..N-1]) which reduces the given symmetric
+                           matrix to tridiagonal form;
+                         * 2, Z isn't used (but changed on the exit).
+
+        Output parameters:
+            D       -   array of the eigenvalues found.
+                        Array whose index ranges within [0..M-1].
+            M       -   number of eigenvalues found in the given half-interval (M>=0).
+            Z       -   if ZNeeded is equal to:
+                         * 0, doesn't contain any information;
+                         * 1, contains the product of a given NxN matrix Z (from the
+                           left) and NxM matrix of the eigenvectors found (from the
+                           right). Array whose indexes range within [0..N-1, 0..M-1].
+                         * 2, contains the matrix of the eigenvectors found.
+                           Array whose indexes range within [0..N-1, 0..M-1].
+
+        Result:
+
+            True, if successful. In that case, M contains the number of eigenvalues
+            in the given half-interval (could be equal to 0), D contains the eigenvalues,
+            Z contains the eigenvectors (if needed).
+            It should be noted that the subroutine changes the size of arrays D and Z.
+
+            False, if the bisection method subroutine wasn't able to find the
+            eigenvalues in the given interval or if the inverse iteration subroutine
+            wasn't able to find all the corresponding eigenvectors. In that case,
+            the eigenvalues and eigenvectors are not returned, M is equal to 0.
+
+          -- ALGLIB --
+             Copyright 31.03.2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixtdevdr(ref double[] d,
+            ref double[] e,
+            int n,
+            int zneeded,
+            double a,
+            double b,
+            ref int m,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            int errorcode = 0;
+            int nsplit = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int cr = 0;
+            int[] iblock = new int[0];
+            int[] isplit = new int[0];
+            int[] ifail = new int[0];
+            double[] d1 = new double[0];
+            double[] e1 = new double[0];
+            double[] w = new double[0];
+            double[,] z2 = new double[0,0];
+            double[,] z3 = new double[0,0];
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(zneeded>=0 & zneeded<=2, "SMatrixTDEVDR: incorrect ZNeeded!");
+            
+            //
+            // Special cases
+            //
+            if( (double)(b)<=(double)(a) )
+            {
+                m = 0;
+                result = true;
+                return result;
+            }
+            if( n<=0 )
+            {
+                m = 0;
+                result = true;
+                return result;
+            }
+            
+            //
+            // Copy D,E to D1, E1
+            //
+            d1 = new double[n+1];
+            i1_ = (0) - (1);
+            for(i_=1; i_<=n;i_++)
+            {
+                d1[i_] = d[i_+i1_];
+            }
+            if( n>1 )
+            {
+                e1 = new double[n-1+1];
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n-1;i_++)
+                {
+                    e1[i_] = e[i_+i1_];
+                }
+            }
+            
+            //
+            // No eigen vectors
+            //
+            if( zneeded==0 )
+            {
+                result = internalbisectioneigenvalues(d1, e1, n, 2, 1, a, b, 0, 0, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result | m==0 )
+                {
+                    m = 0;
+                    return result;
+                }
+                d = new double[m-1+1];
+                i1_ = (1) - (0);
+                for(i_=0; i_<=m-1;i_++)
+                {
+                    d[i_] = w[i_+i1_];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are multiplied by Z
+            //
+            if( zneeded==1 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d1, e1, n, 2, 2, a, b, 0, 0, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result | m==0 )
+                {
+                    m = 0;
+                    return result;
+                }
+                internaldstein(n, ref d1, e1, m, w, ref iblock, ref isplit, ref z2, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    m = 0;
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z2[j,i];
+                        z2[j,i] = z2[j,k];
+                        z2[j,k] = v;
+                    }
+                }
+                
+                //
+                // Transform Z2 and overwrite Z
+                //
+                z3 = new double[m+1, n+1];
+                for(i=1; i<=m; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z3[i,i_] = z2[i_,i];
+                    }
+                }
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=m; j++)
+                    {
+                        i1_ = (1)-(0);
+                        v = 0.0;
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            v += z[i-1,i_]*z3[j,i_+i1_];
+                        }
+                        z2[i,j] = v;
+                    }
+                }
+                z = new double[n-1+1, m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    i1_ = (1) - (0);
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        z[i_,i-1] = z2[i_+i1_,i];
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i-1] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are stored in Z
+            //
+            if( zneeded==2 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d1, e1, n, 2, 2, a, b, 0, 0, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result | m==0 )
+                {
+                    m = 0;
+                    return result;
+                }
+                internaldstein(n, ref d1, e1, m, w, ref iblock, ref isplit, ref z2, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    m = 0;
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z2[j,i];
+                        z2[j,i] = z2[j,k];
+                        z2[j,k] = v;
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i-1] = w[i];
+                }
+                z = new double[n-1+1, m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    i1_ = (1) - (0);
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        z[i_,i-1] = z2[i_+i1_,i];
+                    }
+                }
+                return result;
+            }
+            result = false;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Subroutine for finding tridiagonal matrix eigenvalues/vectors with given
+        indexes (in ascending order) by using the bisection and inverse iteraion.
+
+        Input parameters:
+            D       -   the main diagonal of a tridiagonal matrix.
+                        Array whose index ranges within [0..N-1].
+            E       -   the secondary diagonal of a tridiagonal matrix.
+                        Array whose index ranges within [0..N-2].
+            N       -   size of matrix. N>=0.
+            ZNeeded -   flag controlling whether the eigenvectors are needed or not.
+                        If ZNeeded is equal to:
+                         * 0, the eigenvectors are not needed;
+                         * 1, the eigenvectors of a tridiagonal matrix are multiplied
+                           by the square matrix Z. It is used if the
+                           tridiagonal matrix is obtained by the similarity transformation
+                           of a symmetric matrix.
+                         * 2, the eigenvectors of a tridiagonal matrix replace
+                           matrix Z.
+            I1, I2  -   index interval for searching (from I1 to I2).
+                        0 <= I1 <= I2 <= N-1.
+            Z       -   if ZNeeded is equal to:
+                         * 0, Z isn't used and remains unchanged;
+                         * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1])
+                           which reduces the given symmetric matrix to  tridiagonal form;
+                         * 2, Z isn't used (but changed on the exit).
+
+        Output parameters:
+            D       -   array of the eigenvalues found.
+                        Array whose index ranges within [0..I2-I1].
+            Z       -   if ZNeeded is equal to:
+                         * 0, doesn't contain any information;
+                         * 1, contains the product of a given NxN matrix Z (from the left) and
+                           Nx(I2-I1) matrix of the eigenvectors found (from the right).
+                           Array whose indexes range within [0..N-1, 0..I2-I1].
+                         * 2, contains the matrix of the eigenvalues found.
+                           Array whose indexes range within [0..N-1, 0..I2-I1].
+
+
+        Result:
+
+            True, if successful. In that case, D contains the eigenvalues,
+            Z contains the eigenvectors (if needed).
+            It should be noted that the subroutine changes the size of arrays D and Z.
+
+            False, if the bisection method subroutine wasn't able to find the eigenvalues
+            in the given interval or if the inverse iteration subroutine wasn't able
+            to find all the corresponding eigenvectors. In that case, the eigenvalues
+            and eigenvectors are not returned.
+
+          -- ALGLIB --
+             Copyright 25.12.2005 by Bochkanov Sergey
+        *************************************************************************/
+        public static bool smatrixtdevdi(ref double[] d,
+            ref double[] e,
+            int n,
+            int zneeded,
+            int i1,
+            int i2,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            int errorcode = 0;
+            int nsplit = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int m = 0;
+            int cr = 0;
+            int[] iblock = new int[0];
+            int[] isplit = new int[0];
+            int[] ifail = new int[0];
+            double[] w = new double[0];
+            double[] d1 = new double[0];
+            double[] e1 = new double[0];
+            double[,] z2 = new double[0,0];
+            double[,] z3 = new double[0,0];
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            System.Diagnostics.Debug.Assert(0<=i1 & i1<=i2 & i2<n, "SMatrixTDEVDI: incorrect I1/I2!");
+            
+            //
+            // Copy D,E to D1, E1
+            //
+            d1 = new double[n+1];
+            i1_ = (0) - (1);
+            for(i_=1; i_<=n;i_++)
+            {
+                d1[i_] = d[i_+i1_];
+            }
+            if( n>1 )
+            {
+                e1 = new double[n-1+1];
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n-1;i_++)
+                {
+                    e1[i_] = e[i_+i1_];
+                }
+            }
+            
+            //
+            // No eigen vectors
+            //
+            if( zneeded==0 )
+            {
+                result = internalbisectioneigenvalues(d1, e1, n, 3, 1, 0, 0, i1+1, i2+1, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result )
+                {
+                    return result;
+                }
+                if( m!=i2-i1+1 )
+                {
+                    result = false;
+                    return result;
+                }
+                d = new double[m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i-1] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are multiplied by Z
+            //
+            if( zneeded==1 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d1, e1, n, 3, 2, 0, 0, i1+1, i2+1, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result )
+                {
+                    return result;
+                }
+                if( m!=i2-i1+1 )
+                {
+                    result = false;
+                    return result;
+                }
+                internaldstein(n, ref d1, e1, m, w, ref iblock, ref isplit, ref z2, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z2[j,i];
+                        z2[j,i] = z2[j,k];
+                        z2[j,k] = v;
+                    }
+                }
+                
+                //
+                // Transform Z2 and overwrite Z
+                //
+                z3 = new double[m+1, n+1];
+                for(i=1; i<=m; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z3[i,i_] = z2[i_,i];
+                    }
+                }
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=m; j++)
+                    {
+                        i1_ = (1)-(0);
+                        v = 0.0;
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            v += z[i-1,i_]*z3[j,i_+i1_];
+                        }
+                        z2[i,j] = v;
+                    }
+                }
+                z = new double[n-1+1, m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    i1_ = (1) - (0);
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        z[i_,i-1] = z2[i_+i1_,i];
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i-1] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are stored in Z
+            //
+            if( zneeded==2 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d1, e1, n, 3, 2, 0, 0, i1+1, i2+1, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result )
+                {
+                    return result;
+                }
+                if( m!=i2-i1+1 )
+                {
+                    result = false;
+                    return result;
+                }
+                internaldstein(n, ref d1, e1, m, w, ref iblock, ref isplit, ref z2, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z2[j,i];
+                        z2[j,i] = z2[j,k];
+                        z2[j,k] = v;
+                    }
+                }
+                
+                //
+                // Store Z
+                //
+                z = new double[n-1+1, m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    i1_ = (1) - (0);
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        z[i_,i-1] = z2[i_+i1_,i];
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m-1+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i-1] = w[i];
+                }
+                return result;
+            }
+            result = false;
+            return result;
+        }
+
+
+        public static bool tridiagonaleigenvaluesandvectorsininterval(ref double[] d,
+            ref double[] e,
+            int n,
+            int zneeded,
+            double a,
+            double b,
+            ref int m,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            int errorcode = 0;
+            int nsplit = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int cr = 0;
+            int[] iblock = new int[0];
+            int[] isplit = new int[0];
+            int[] ifail = new int[0];
+            double[] w = new double[0];
+            double[,] z2 = new double[0,0];
+            double[,] z3 = new double[0,0];
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            // No eigen vectors
+            //
+            if( zneeded==0 )
+            {
+                result = internalbisectioneigenvalues(d, e, n, 2, 1, a, b, 0, 0, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result | m==0 )
+                {
+                    m = 0;
+                    return result;
+                }
+                d = new double[m+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are multiplied by Z
+            //
+            if( zneeded==1 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d, e, n, 2, 2, a, b, 0, 0, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result | m==0 )
+                {
+                    m = 0;
+                    return result;
+                }
+                internaldstein(n, ref d, e, m, w, ref iblock, ref isplit, ref z2, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    m = 0;
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z2[j,i];
+                        z2[j,i] = z2[j,k];
+                        z2[j,k] = v;
+                    }
+                }
+                
+                //
+                // Transform Z2 and overwrite Z
+                //
+                z3 = new double[m+1, n+1];
+                for(i=1; i<=m; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z3[i,i_] = z2[i_,i];
+                    }
+                }
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=m; j++)
+                    {
+                        v = 0.0;
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            v += z[i,i_]*z3[j,i_];
+                        }
+                        z2[i,j] = v;
+                    }
+                }
+                z = new double[n+1, m+1];
+                for(i=1; i<=m; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z[i_,i] = z2[i_,i];
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are stored in Z
+            //
+            if( zneeded==2 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d, e, n, 2, 2, a, b, 0, 0, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result | m==0 )
+                {
+                    m = 0;
+                    return result;
+                }
+                internaldstein(n, ref d, e, m, w, ref iblock, ref isplit, ref z, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    m = 0;
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z[j,i];
+                        z[j,i] = z[j,k];
+                        z[j,k] = v;
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i] = w[i];
+                }
+                return result;
+            }
+            result = false;
+            return result;
+        }
+
+
+        public static bool tridiagonaleigenvaluesandvectorsbyindexes(ref double[] d,
+            ref double[] e,
+            int n,
+            int zneeded,
+            int i1,
+            int i2,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            int errorcode = 0;
+            int nsplit = 0;
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int m = 0;
+            int cr = 0;
+            int[] iblock = new int[0];
+            int[] isplit = new int[0];
+            int[] ifail = new int[0];
+            double[] w = new double[0];
+            double[,] z2 = new double[0,0];
+            double[,] z3 = new double[0,0];
+            double v = 0;
+            int i_ = 0;
+
+            
+            //
+            // No eigen vectors
+            //
+            if( zneeded==0 )
+            {
+                result = internalbisectioneigenvalues(d, e, n, 3, 1, 0, 0, i1, i2, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result )
+                {
+                    return result;
+                }
+                d = new double[m+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are multiplied by Z
+            //
+            if( zneeded==1 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d, e, n, 3, 2, 0, 0, i1, i2, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result )
+                {
+                    return result;
+                }
+                internaldstein(n, ref d, e, m, w, ref iblock, ref isplit, ref z2, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z2[j,i];
+                        z2[j,i] = z2[j,k];
+                        z2[j,k] = v;
+                    }
+                }
+                
+                //
+                // Transform Z2 and overwrite Z
+                //
+                z3 = new double[m+1, n+1];
+                for(i=1; i<=m; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z3[i,i_] = z2[i_,i];
+                    }
+                }
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=m; j++)
+                    {
+                        v = 0.0;
+                        for(i_=1; i_<=n;i_++)
+                        {
+                            v += z[i,i_]*z3[j,i_];
+                        }
+                        z2[i,j] = v;
+                    }
+                }
+                z = new double[n+1, m+1];
+                for(i=1; i<=m; i++)
+                {
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z[i_,i] = z2[i_,i];
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i] = w[i];
+                }
+                return result;
+            }
+            
+            //
+            // Eigen vectors are stored in Z
+            //
+            if( zneeded==2 )
+            {
+                
+                //
+                // Find eigen pairs
+                //
+                result = internalbisectioneigenvalues(d, e, n, 3, 2, 0, 0, i1, i2, -1, ref w, ref m, ref nsplit, ref iblock, ref isplit, ref errorcode);
+                if( !result )
+                {
+                    return result;
+                }
+                internaldstein(n, ref d, e, m, w, ref iblock, ref isplit, ref z, ref ifail, ref cr);
+                if( cr!=0 )
+                {
+                    result = false;
+                    return result;
+                }
+                
+                //
+                // Sort eigen values and vectors
+                //
+                for(i=1; i<=m; i++)
+                {
+                    k = i;
+                    for(j=i; j<=m; j++)
+                    {
+                        if( (double)(w[j])<(double)(w[k]) )
+                        {
+                            k = j;
+                        }
+                    }
+                    v = w[i];
+                    w[i] = w[k];
+                    w[k] = v;
+                    for(j=1; j<=n; j++)
+                    {
+                        v = z[j,i];
+                        z[j,i] = z[j,k];
+                        z[j,k] = v;
+                    }
+                }
+                
+                //
+                // Store W
+                //
+                d = new double[m+1];
+                for(i=1; i<=m; i++)
+                {
+                    d[i] = w[i];
+                }
+                return result;
+            }
+            result = false;
+            return result;
+        }
+
+
+        public static bool internalbisectioneigenvalues(double[] d,
+            double[] e,
+            int n,
+            int irange,
+            int iorder,
+            double vl,
+            double vu,
+            int il,
+            int iu,
+            double abstol,
+            ref double[] w,
+            ref int m,
+            ref int nsplit,
+            ref int[] iblock,
+            ref int[] isplit,
+            ref int errorcode)
+        {
+            bool result = new bool();
+            double fudge = 0;
+            double relfac = 0;
+            bool ncnvrg = new bool();
+            bool toofew = new bool();
+            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;
+            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;
+            int[] idumma = new int[0];
+            double[] work = new double[0];
+            int[] iwork = new int[0];
+            int[] ia1s2 = new int[0];
+            double[] ra1s2 = new double[0];
+            double[,] ra1s2x2 = new double[0,0];
+            int[,] ia1s2x2 = new int[0,0];
+            double[] ra1siin = new double[0];
+            double[] ra2siin = new double[0];
+            double[] ra3siin = new double[0];
+            double[] ra4siin = new double[0];
+            double[,] ra1siinx2 = new double[0,0];
+            int[,] ia1siinx2 = new int[0,0];
+            int[] iworkspace = new int[0];
+            double[] rworkspace = new double[0];
+            int tmpi = 0;
+
+            d = (double[])d.Clone();
+            e = (double[])e.Clone();
+
+            
+            //
+            // Quick return if possible
+            //
+            m = 0;
+            if( n==0 )
+            {
+                result = true;
+                return result;
+            }
+            
+            //
+            // 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 = AP.Math.MinRealNumber;
+            ulp = 2*AP.Math.MachineEpsilon;
+            rtoli = ulp*relfac;
+            idumma = new int[1+1];
+            work = new double[4*n+1];
+            iwork = new int[3*n+1];
+            w = new double[n+1];
+            iblock = new int[n+1];
+            isplit = new int[n+1];
+            ia1s2 = new int[2+1];
+            ra1s2 = new double[2+1];
+            ra1s2x2 = new double[2+1, 2+1];
+            ia1s2x2 = new int[2+1, 2+1];
+            ra1siin = new double[n+1];
+            ra2siin = new double[n+1];
+            ra3siin = new double[n+1];
+            ra4siin = new double[n+1];
+            ra1siinx2 = new double[n+1, 2+1];
+            ia1siinx2 = new int[n+1, 2+1];
+            iworkspace = new int[n+1];
+            rworkspace = new double[n+1];
+            
+            //
+            // Check for Errors
+            //
+            result = false;
+            errorcode = 0;
+            if( irange<=0 | irange>=4 )
+            {
+                errorcode = -4;
+            }
+            if( iorder<=0 | iorder>=3 )
+            {
+                errorcode = -5;
+            }
+            if( n<0 )
+            {
+                errorcode = -3;
+            }
+            if( irange==2 & (double)(vl)>=(double)(vu) )
+            {
+                errorcode = -6;
+            }
+            if( irange==3 & (il<1 | il>Math.Max(1, n)) )
+            {
+                errorcode = -8;
+            }
+            if( irange==3 & (iu<Math.Min(n, il) | iu>n) )
+            {
+                errorcode = -9;
+            }
+            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;
+                if( irange==2 & ((double)(vl)>=(double)(d[1]) | (double)(vu)<(double)(d[1])) )
+                {
+                    m = 0;
+                }
+                else
+                {
+                    w[1] = d[1];
+                    iblock[1] = 1;
+                    m = 1;
+                }
+                result = true;
+                return result;
+            }
+            
+            //
+            // Scaling
+            //
+            t = Math.Abs(d[n]);
+            for(j=1; j<=n-1; j++)
+            {
+                t = Math.Max(t, Math.Abs(d[j]));
+                t = Math.Max(t, Math.Abs(e[j]));
+            }
+            scalefactor = 1;
+            if( (double)(t)!=(double)(0) )
+            {
+                if( (double)(t)>(double)(Math.Sqrt(Math.Sqrt(AP.Math.MinRealNumber))*Math.Sqrt(AP.Math.MaxRealNumber)) )
+                {
+                    scalefactor = t;
+                }
+                if( (double)(t)<(double)(Math.Sqrt(Math.Sqrt(AP.Math.MaxRealNumber))*Math.Sqrt(AP.Math.MinRealNumber)) )
+                {
+                    scalefactor = t;
+                }
+                for(j=1; j<=n-1; j++)
+                {
+                    d[j] = d[j]/scalefactor;
+                    e[j] = e[j]/scalefactor;
+                }
+                d[n] = d[n]/scalefactor;
+            }
+            
+            //
+            // Compute Splitting Points
+            //
+            nsplit = 1;
+            work[n] = 0;
+            pivmin = 1;
+            for(j=2; j<=n; j++)
+            {
+                tmp1 = AP.Math.Sqr(e[j-1]);
+                if( (double)(Math.Abs(d[j]*d[j-1])*AP.Math.Sqr(ulp)+safemn)>(double)(tmp1) )
+                {
+                    isplit[nsplit] = j-1;
+                    nsplit = nsplit+1;
+                    work[j-1] = 0;
+                }
+                else
+                {
+                    work[j-1] = tmp1;
+                    pivmin = Math.Max(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-1; j++)
+                {
+                    tmp2 = Math.Sqrt(work[j]);
+                    gu = Math.Max(gu, d[j]+tmp1+tmp2);
+                    gl = Math.Min(gl, d[j]-tmp1-tmp2);
+                    tmp1 = tmp2;
+                }
+                gu = Math.Max(gu, d[n]+tmp1);
+                gl = Math.Min(gl, d[n]-tmp1);
+                tnorm = Math.Max(Math.Abs(gl), Math.Abs(gu));
+                gl = gl-fudge*tnorm*ulp*n-fudge*2*pivmin;
+                gu = gu+fudge*tnorm*ulp*n+fudge*pivmin;
+                
+                //
+                // Compute Iteration parameters
+                //
+                itmax = (int)Math.Ceiling((Math.Log(tnorm+pivmin)-Math.Log(pivmin))/Math.Log(2))+2;
+                if( (double)(abstol)<=(double)(0) )
+                {
+                    atoli = ulp*tnorm;
+                }
+                else
+                {
+                    atoli = abstol;
+                }
+                work[n+1] = gl;
+                work[n+2] = gl;
+                work[n+3] = gu;
+                work[n+4] = gu;
+                work[n+5] = gl;
+                work[n+6] = gu;
+                iwork[1] = -1;
+                iwork[2] = -1;
+                iwork[3] = n+1;
+                iwork[4] = n+1;
+                iwork[5] = il-1;
+                iwork[6] = iu;
+                
+                //
+                // Calling DLAEBZ
+                //
+                // DLAEBZ( 3, ITMAX, N, 2, 2, NB, ATOLI, RTOLI, PIVMIN, D, E,
+                //    WORK, IWORK( 5 ), WORK( N+1 ), WORK( N+5 ), IOUT,
+                //    IWORK, W, IBLOCK, IINFO )
+                //
+                ia1s2[1] = iwork[5];
+                ia1s2[2] = iwork[6];
+                ra1s2[1] = work[n+5];
+                ra1s2[2] = work[n+6];
+                ra1s2x2[1,1] = work[n+1];
+                ra1s2x2[2,1] = work[n+2];
+                ra1s2x2[1,2] = work[n+3];
+                ra1s2x2[2,2] = work[n+4];
+                ia1s2x2[1,1] = iwork[1];
+                ia1s2x2[2,1] = iwork[2];
+                ia1s2x2[1,2] = iwork[3];
+                ia1s2x2[2,2] = iwork[4];
+                internaldlaebz(3, itmax, n, 2, 2, atoli, rtoli, pivmin, ref d, ref e, ref work, ref ia1s2, ref ra1s2x2, ref ra1s2, ref iout, ref ia1s2x2, ref w, ref iblock, ref iinfo);
+                iwork[5] = ia1s2[1];
+                iwork[6] = ia1s2[2];
+                work[n+5] = ra1s2[1];
+                work[n+6] = ra1s2[2];
+                work[n+1] = ra1s2x2[1,1];
+                work[n+2] = ra1s2x2[2,1];
+                work[n+3] = ra1s2x2[1,2];
+                work[n+4] = ra1s2x2[2,2];
+                iwork[1] = ia1s2x2[1,1];
+                iwork[2] = ia1s2x2[2,1];
+                iwork[3] = ia1s2x2[1,2];
+                iwork[4] = ia1s2x2[2,2];
+                if( iwork[6]==iu )
+                {
+                    wl = work[n+1];
+                    wlu = work[n+3];
+                    nwl = iwork[1];
+                    wu = work[n+4];
+                    wul = work[n+2];
+                    nwu = iwork[4];
+                }
+                else
+                {
+                    wl = work[n+2];
+                    wlu = work[n+4];
+                    nwl = iwork[2];
+                    wu = work[n+3];
+                    wul = work[n+1];
+                    nwu = iwork[3];
+                }
+                if( nwl<0 | nwl>=n | nwu<1 | nwu>n )
+                {
+                    errorcode = 4;
+                    result = false;
+                    return result;
+                }
+            }
+            else
+            {
+                
+                //
+                // RANGE='A' or 'V' -- Set ATOLI
+                //
+                tnorm = Math.Max(Math.Abs(d[1])+Math.Abs(e[1]), Math.Abs(d[n])+Math.Abs(e[n-1]));
+                for(j=2; j<=n-1; j++)
+                {
+                    tnorm = Math.Max(tnorm, Math.Abs(d[j])+Math.Abs(e[j-1])+Math.Abs(e[j]));
+                }
+                if( (double)(abstol)<=(double)(0) )
+                {
+                    atoli = ulp*tnorm;
+                }
+                else
+                {
+                    atoli = abstol;
+                }
+                if( irange==2 )
+                {
+                    wl = vl;
+                    wu = vu;
+                }
+                else
+                {
+                    wl = 0;
+                    wu = 0;
+                }
+            }
+            
+            //
+            // Find Eigenvalues -- Loop Over Blocks and recompute NWL and NWU.
+            // NWL accumulates the number of eigenvalues .le. WL,
+            // NWU accumulates the number of eigenvalues .le. WU
+            //
+            m = 0;
+            iend = 0;
+            errorcode = 0;
+            nwl = 0;
+            nwu = 0;
+            for(jb=1; jb<=nsplit; jb++)
+            {
+                ioff = iend;
+                ibegin = ioff+1;
+                iend = isplit[jb];
+                iin = iend-ioff;
+                if( iin==1 )
+                {
+                    
+                    //
+                    // Special Case -- IIN=1
+                    //
+                    if( irange==1 | (double)(wl)>=(double)(d[ibegin]-pivmin) )
+                    {
+                        nwl = nwl+1;
+                    }
+                    if( irange==1 | (double)(wu)>=(double)(d[ibegin]-pivmin) )
+                    {
+                        nwu = nwu+1;
+                    }
+                    if( irange==1 | (double)(wl)<(double)(d[ibegin]-pivmin) & (double)(wu)>=(double)(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++)
+                    {
+                        tmp2 = Math.Abs(e[j]);
+                        gu = Math.Max(gu, d[j]+tmp1+tmp2);
+                        gl = Math.Min(gl, d[j]-tmp1-tmp2);
+                        tmp1 = tmp2;
+                    }
+                    gu = Math.Max(gu, d[iend]+tmp1);
+                    gl = Math.Min(gl, d[iend]-tmp1);
+                    bnorm = Math.Max(Math.Abs(gl), Math.Abs(gu));
+                    gl = gl-fudge*bnorm*ulp*iin-fudge*pivmin;
+                    gu = gu+fudge*bnorm*ulp*iin+fudge*pivmin;
+                    
+                    //
+                    // Compute ATOLI for the current submatrix
+                    //
+                    if( (double)(abstol)<=(double)(0) )
+                    {
+                        atoli = ulp*Math.Max(Math.Abs(gl), Math.Abs(gu));
+                    }
+                    else
+                    {
+                        atoli = abstol;
+                    }
+                    if( irange>1 )
+                    {
+                        if( (double)(gu)<(double)(wl) )
+                        {
+                            nwl = nwl+iin;
+                            nwu = nwu+iin;
+                            continue;
+                        }
+                        gl = Math.Max(gl, wl);
+                        gu = Math.Min(gu, wu);
+                        if( (double)(gl)>=(double)(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];
+                        if( ibegin-1+tmpi<n )
+                        {
+                            ra2siin[tmpi] = e[ibegin-1+tmpi];
+                        }
+                        ra3siin[tmpi] = work[ibegin-1+tmpi];
+                        ra1siinx2[tmpi,1] = work[n+tmpi];
+                        ra1siinx2[tmpi,2] = work[n+tmpi+iin];
+                        ra4siin[tmpi] = work[n+2*iin+tmpi];
+                        rworkspace[tmpi] = w[m+tmpi];
+                        iworkspace[tmpi] = iblock[m+tmpi];
+                        ia1siinx2[tmpi,1] = iwork[tmpi];
+                        ia1siinx2[tmpi,2] = iwork[tmpi+iin];
+                    }
+                    internaldlaebz(1, 0, iin, iin, 1, atoli, rtoli, pivmin, ref ra1siin, ref ra2siin, ref ra3siin, ref idumma, ref ra1siinx2, ref ra4siin, ref im, ref ia1siinx2, ref rworkspace, ref iworkspace, ref iinfo);
+                    for(tmpi=1; tmpi<=iin; tmpi++)
+                    {
+                        work[n+tmpi] = ra1siinx2[tmpi,1];
+                        work[n+tmpi+iin] = ra1siinx2[tmpi,2];
+                        work[n+2*iin+tmpi] = ra4siin[tmpi];
+                        w[m+tmpi] = rworkspace[tmpi];
+                        iblock[m+tmpi] = iworkspace[tmpi];
+                        iwork[tmpi] = ia1siinx2[tmpi,1];
+                        iwork[tmpi+iin] = ia1siinx2[tmpi,2];
+                    }
+                    nwl = nwl+iwork[1];
+                    nwu = nwu+iwork[iin+1];
+                    iwoff = m-iwork[1];
+                    
+                    //
+                    // Compute Eigenvalues
+                    //
+                    itmax = (int)Math.Ceiling((Math.Log(gu-gl+pivmin)-Math.Log(pivmin))/Math.Log(2))+2;
+                    
+                    //
+                    // Calling DLAEBZ
+                    //
+                    //CALL DLAEBZ( 2, ITMAX, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN,
+                    //    D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ),
+                    //    IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IOUT,
+                    //    IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO )
+                    //
+                    for(tmpi=1; tmpi<=iin; tmpi++)
+                    {
+                        ra1siin[tmpi] = d[ibegin-1+tmpi];
+                        if( ibegin-1+tmpi<n )
+                        {
+                            ra2siin[tmpi] = e[ibegin-1+tmpi];
+                        }
+                        ra3siin[tmpi] = work[ibegin-1+tmpi];
+                        ra1siinx2[tmpi,1] = work[n+tmpi];
+                        ra1siinx2[tmpi,2] = work[n+tmpi+iin];
+                        ra4siin[tmpi] = work[n+2*iin+tmpi];
+                        rworkspace[tmpi] = w[m+tmpi];
+                        iworkspace[tmpi] = iblock[m+tmpi];
+                        ia1siinx2[tmpi,1] = iwork[tmpi];
+                        ia1siinx2[tmpi,2] = iwork[tmpi+iin];
+                    }
+                    internaldlaebz(2, itmax, iin, iin, 1, atoli, rtoli, pivmin, ref ra1siin, ref ra2siin, ref ra3siin, ref idumma, ref ra1siinx2, ref ra4siin, ref iout, ref ia1siinx2, ref rworkspace, ref iworkspace, ref iinfo);
+                    for(tmpi=1; tmpi<=iin; tmpi++)
+                    {
+                        work[n+tmpi] = ra1siinx2[tmpi,1];
+                        work[n+tmpi+iin] = ra1siinx2[tmpi,2];
+                        work[n+2*iin+tmpi] = ra4siin[tmpi];
+                        w[m+tmpi] = rworkspace[tmpi];
+                        iblock[m+tmpi] = iworkspace[tmpi];
+                        iwork[tmpi] = ia1siinx2[tmpi,1];
+                        iwork[tmpi+iin] = ia1siinx2[tmpi,2];
+                    }
+                    
+                    //
+                    // Copy Eigenvalues Into W and IBLOCK
+                    // Use -JB for block number for unconverged eigenvalues.
+                    //
+                    for(j=1; j<=iout; j++)
+                    {
+                        tmp1 = 0.5*(work[j+n]+work[j+iin+n]);
+                        
+                        //
+                        // Flag non-convergence.
+                        //
+                        if( j>iout-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;
+                if( idiscl>0 | idiscu>0 )
+                {
+                    for(je=1; je<=m; je++)
+                    {
+                        if( (double)(w[je])<=(double)(wlu) & idiscl>0 )
+                        {
+                            idiscl = idiscl-1;
+                        }
+                        else
+                        {
+                            if( (double)(w[je])>=(double)(wul) & idiscu>0 )
+                            {
+                                idiscu = idiscu-1;
+                            }
+                            else
+                            {
+                                im = im+1;
+                                w[im] = w[je];
+                                iblock[im] = iblock[je];
+                            }
+                        }
+                    }
+                    m = im;
+                }
+                if( idiscl>0 | idiscu>0 )
+                {
+                    
+                    //
+                    // Code to deal with effects of bad arithmetic:
+                    // Some low eigenvalues to be discarded are not in (WL,WLU],
+                    // or high eigenvalues to be discarded are not in (WUL,WU]
+                    // so just kill off the smallest IDISCL/largest IDISCU
+                    // eigenvalues, by simply finding the smallest/largest
+                    // eigenvalue(s).
+                    //
+                    // (If N(w) is monotone non-decreasing, this should never
+                    //  happen.)
+                    //
+                    if( idiscl>0 )
+                    {
+                        wkill = wu;
+                        for(jdisc=1; jdisc<=idiscl; jdisc++)
+                        {
+                            iw = 0;
+                            for(je=1; je<=m; je++)
+                            {
+                                if( iblock[je]!=0 & ((double)(w[je])<(double)(wkill) | iw==0) )
+                                {
+                                    iw = je;
+                                    wkill = w[je];
+                                }
+                            }
+                            iblock[iw] = 0;
+                        }
+                    }
+                    if( idiscu>0 )
+                    {
+                        wkill = wl;
+                        for(jdisc=1; jdisc<=idiscu; jdisc++)
+                        {
+                            iw = 0;
+                            for(je=1; je<=m; je++)
+                            {
+                                if( iblock[je]!=0 & ((double)(w[je])>(double)(wkill) | iw==0) )
+                                {
+                                    iw = je;
+                                    wkill = w[je];
+                                }
+                            }
+                            iblock[iw] = 0;
+                        }
+                    }
+                    im = 0;
+                    for(je=1; je<=m; je++)
+                    {
+                        if( iblock[je]!=0 )
+                        {
+                            im = im+1;
+                            w[im] = w[je];
+                            iblock[im] = iblock[je];
+                        }
+                    }
+                    m = im;
+                }
+                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++)
+                    {
+                        if( (double)(w[j])<(double)(tmp1) )
+                        {
+                            ie = j;
+                            tmp1 = w[j];
+                        }
+                    }
+                    if( ie!=0 )
+                    {
+                        itmp1 = iblock[ie];
+                        w[ie] = w[je];
+                        iblock[ie] = iblock[je];
+                        w[je] = tmp1;
+                        iblock[je] = itmp1;
+                    }
+                }
+            }
+            for(j=1; j<=m; j++)
+            {
+                w[j] = w[j]*scalefactor;
+            }
+            errorcode = 0;
+            if( ncnvrg )
+            {
+                errorcode = errorcode+1;
+            }
+            if( toofew )
+            {
+                errorcode = errorcode+2;
+            }
+            result = errorcode==0;
+            return result;
+        }
+
+
+        public static void internaldstein(int n,
+            ref double[] d,
+            double[] e,
+            int m,
+            double[] w,
+            ref int[] iblock,
+            ref int[] isplit,
+            ref double[,] z,
+            ref int[] ifail,
+            ref int info)
+        {
+            int maxits = 0;
+            int extra = 0;
+            int b1 = 0;
+            int blksiz = 0;
+            int bn = 0;
+            int gpind = 0;
+            int i = 0;
+            int iinfo = 0;
+            int its = 0;
+            int j = 0;
+            int j1 = 0;
+            int jblk = 0;
+            int jmax = 0;
+            int nblk = 0;
+            int nrmchk = 0;
+            double dtpcrt = 0;
+            double eps = 0;
+            double eps1 = 0;
+            double nrm = 0;
+            double onenrm = 0;
+            double ortol = 0;
+            double pertol = 0;
+            double scl = 0;
+            double sep = 0;
+            double tol = 0;
+            double xj = 0;
+            double xjm = 0;
+            double ztr = 0;
+            double[] work1 = new double[0];
+            double[] work2 = new double[0];
+            double[] work3 = new double[0];
+            double[] work4 = new double[0];
+            double[] work5 = new double[0];
+            int[] iwork = new int[0];
+            bool tmpcriterion = new bool();
+            int ti = 0;
+            int i1 = 0;
+            int i2 = 0;
+            double v = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            e = (double[])e.Clone();
+            w = (double[])w.Clone();
+
+            maxits = 5;
+            extra = 2;
+            work1 = new double[Math.Max(n, 1)+1];
+            work2 = new double[Math.Max(n-1, 1)+1];
+            work3 = new double[Math.Max(n, 1)+1];
+            work4 = new double[Math.Max(n, 1)+1];
+            work5 = new double[Math.Max(n, 1)+1];
+            iwork = new int[Math.Max(n, 1)+1];
+            ifail = new int[Math.Max(m, 1)+1];
+            z = new double[Math.Max(n, 1)+1, Math.Max(m, 1)+1];
+            
+            //
+            // Test the input parameters.
+            //
+            info = 0;
+            for(i=1; i<=m; i++)
+            {
+                ifail[i] = 0;
+            }
+            if( n<0 )
+            {
+                info = -1;
+                return;
+            }
+            if( m<0 | m>n )
+            {
+                info = -4;
+                return;
+            }
+            for(j=2; j<=m; j++)
+            {
+                if( iblock[j]<iblock[j-1] )
+                {
+                    info = -6;
+                    break;
+                }
+                if( iblock[j]==iblock[j-1] & (double)(w[j])<(double)(w[j-1]) )
+                {
+                    info = -5;
+                    break;
+                }
+            }
+            if( info!=0 )
+            {
+                return;
+            }
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 | m==0 )
+            {
+                return;
+            }
+            if( n==1 )
+            {
+                z[1,1] = 1;
+                return;
+            }
+            
+            //
+            // Some preparations
+            //
+            ti = n-1;
+            for(i_=1; i_<=ti;i_++)
+            {
+                work1[i_] = e[i_];
+            }
+            e = new double[n+1];
+            for(i_=1; i_<=ti;i_++)
+            {
+                e[i_] = work1[i_];
+            }
+            for(i_=1; i_<=m;i_++)
+            {
+                work1[i_] = w[i_];
+            }
+            w = new double[n+1];
+            for(i_=1; i_<=m;i_++)
+            {
+                w[i_] = work1[i_];
+            }
+            
+            //
+            // Get machine constants.
+            //
+            eps = AP.Math.MachineEpsilon;
+            
+            //
+            // Compute eigenvectors of matrix blocks.
+            //
+            j1 = 1;
+            for(nblk=1; nblk<=iblock[m]; nblk++)
+            {
+                
+                //
+                // Find starting and ending indices of block nblk.
+                //
+                if( nblk==1 )
+                {
+                    b1 = 1;
+                }
+                else
+                {
+                    b1 = isplit[nblk-1]+1;
+                }
+                bn = isplit[nblk];
+                blksiz = bn-b1+1;
+                if( blksiz!=1 )
+                {
+                    
+                    //
+                    // Compute reorthogonalization criterion and stopping criterion.
+                    //
+                    gpind = b1;
+                    onenrm = Math.Abs(d[b1])+Math.Abs(e[b1]);
+                    onenrm = Math.Max(onenrm, Math.Abs(d[bn])+Math.Abs(e[bn-1]));
+                    for(i=b1+1; i<=bn-1; i++)
+                    {
+                        onenrm = Math.Max(onenrm, Math.Abs(d[i])+Math.Abs(e[i-1])+Math.Abs(e[i]));
+                    }
+                    ortol = 0.001*onenrm;
+                    dtpcrt = Math.Sqrt(0.1/blksiz);
+                }
+                
+                //
+                // Loop through eigenvalues of block nblk.
+                //
+                jblk = 0;
+                for(j=j1; j<=m; j++)
+                {
+                    if( iblock[j]!=nblk )
+                    {
+                        j1 = j;
+                        break;
+                    }
+                    jblk = jblk+1;
+                    xj = w[j];
+                    if( blksiz==1 )
+                    {
+                        
+                        //
+                        // Skip all the work if the block size is one.
+                        //
+                        work1[1] = 1;
+                    }
+                    else
+                    {
+                        
+                        //
+                        // If eigenvalues j and j-1 are too close, add a relatively
+                        // small perturbation.
+                        //
+                        if( jblk>1 )
+                        {
+                            eps1 = Math.Abs(eps*xj);
+                            pertol = 10*eps1;
+                            sep = xj-xjm;
+                            if( (double)(sep)<(double)(pertol) )
+                            {
+                                xj = xjm+pertol;
+                            }
+                        }
+                        its = 0;
+                        nrmchk = 0;
+                        
+                        //
+                        // Get random starting vector.
+                        //
+                        for(ti=1; ti<=blksiz; ti++)
+                        {
+                            work1[ti] = 2*AP.Math.RandomReal()-1;
+                        }
+                        
+                        //
+                        // Copy the matrix T so it won't be destroyed in factorization.
+                        //
+                        for(ti=1; ti<=blksiz-1; ti++)
+                        {
+                            work2[ti] = e[b1+ti-1];
+                            work3[ti] = e[b1+ti-1];
+                            work4[ti] = d[b1+ti-1];
+                        }
+                        work4[blksiz] = d[b1+blksiz-1];
+                        
+                        //
+                        // Compute LU factors with partial pivoting  ( PT = LU )
+                        //
+                        tol = 0;
+                        tdininternaldlagtf(blksiz, ref work4, xj, ref work2, ref work3, tol, ref work5, ref iwork, ref iinfo);
+                        
+                        //
+                        // Update iteration count.
+                        //
+                        do
+                        {
+                            its = its+1;
+                            if( its>maxits )
+                            {
+                                
+                                //
+                                // If stopping criterion was not satisfied, update info and
+                                // store eigenvector number in array ifail.
+                                //
+                                info = info+1;
+                                ifail[info] = j;
+                                break;
+                            }
+                            
+                            //
+                            // Normalize and scale the righthand side vector Pb.
+                            //
+                            v = 0;
+                            for(ti=1; ti<=blksiz; ti++)
+                            {
+                                v = v+Math.Abs(work1[ti]);
+                            }
+                            scl = blksiz*onenrm*Math.Max(eps, Math.Abs(work4[blksiz]))/v;
+                            for(i_=1; i_<=blksiz;i_++)
+                            {
+                                work1[i_] = scl*work1[i_];
+                            }
+                            
+                            //
+                            // Solve the system LU = Pb.
+                            //
+                            tdininternaldlagts(blksiz, ref work4, ref work2, ref work3, ref work5, ref iwork, ref work1, ref tol, ref iinfo);
+                            
+                            //
+                            // Reorthogonalize by modified Gram-Schmidt if eigenvalues are
+                            // close enough.
+                            //
+                            if( jblk!=1 )
+                            {
+                                if( (double)(Math.Abs(xj-xjm))>(double)(ortol) )
+                                {
+                                    gpind = j;
+                                }
+                                if( gpind!=j )
+                                {
+                                    for(i=gpind; i<=j-1; i++)
+                                    {
+                                        i1 = b1;
+                                        i2 = b1+blksiz-1;
+                                        i1_ = (i1)-(1);
+                                        ztr = 0.0;
+                                        for(i_=1; i_<=blksiz;i_++)
+                                        {
+                                            ztr += work1[i_]*z[i_+i1_,i];
+                                        }
+                                        i1_ = (i1) - (1);
+                                        for(i_=1; i_<=blksiz;i_++)
+                                        {
+                                            work1[i_] = work1[i_] - ztr*z[i_+i1_,i];
+                                        }
+                                    }
+                                }
+                            }
+                            
+                            //
+                            // Check the infinity norm of the iterate.
+                            //
+                            jmax = blas.vectoridxabsmax(ref work1, 1, blksiz);
+                            nrm = Math.Abs(work1[jmax]);
+                            
+                            //
+                            // Continue for additional iterations after norm reaches
+                            // stopping criterion.
+                            //
+                            tmpcriterion = false;
+                            if( (double)(nrm)<(double)(dtpcrt) )
+                            {
+                                tmpcriterion = true;
+                            }
+                            else
+                            {
+                                nrmchk = nrmchk+1;
+                                if( nrmchk<extra+1 )
+                                {
+                                    tmpcriterion = true;
+                                }
+                            }
+                        }
+                        while( tmpcriterion );
+                        
+                        //
+                        // Accept iterate as jth eigenvector.
+                        //
+                        scl = 1/blas.vectornorm2(ref work1, 1, blksiz);
+                        jmax = blas.vectoridxabsmax(ref work1, 1, blksiz);
+                        if( (double)(work1[jmax])<(double)(0) )
+                        {
+                            scl = -scl;
+                        }
+                        for(i_=1; i_<=blksiz;i_++)
+                        {
+                            work1[i_] = scl*work1[i_];
+                        }
+                    }
+                    for(i=1; i<=n; i++)
+                    {
+                        z[i,j] = 0;
+                    }
+                    for(i=1; i<=blksiz; i++)
+                    {
+                        z[b1+i-1,j] = work1[i];
+                    }
+                    
+                    //
+                    // Save the shift to check eigenvalue spacing at next
+                    // iteration.
+                    //
+                    xjm = xj;
+                }
+            }
+        }
+
+
+        private static void tdininternaldlagtf(int n,
+            ref double[] a,
+            double lambda,
+            ref double[] b,
+            ref double[] c,
+            double tol,
+            ref double[] d,
+            ref int[] iin,
+            ref int info)
+        {
+            int k = 0;
+            double eps = 0;
+            double mult = 0;
+            double piv1 = 0;
+            double piv2 = 0;
+            double scale1 = 0;
+            double scale2 = 0;
+            double temp = 0;
+            double tl = 0;
+
+            info = 0;
+            if( n<0 )
+            {
+                info = -1;
+                return;
+            }
+            if( n==0 )
+            {
+                return;
+            }
+            a[1] = a[1]-lambda;
+            iin[n] = 0;
+            if( n==1 )
+            {
+                if( (double)(a[1])==(double)(0) )
+                {
+                    iin[1] = 1;
+                }
+                return;
+            }
+            eps = AP.Math.MachineEpsilon;
+            tl = Math.Max(tol, eps);
+            scale1 = Math.Abs(a[1])+Math.Abs(b[1]);
+            for(k=1; k<=n-1; k++)
+            {
+                a[k+1] = a[k+1]-lambda;
+                scale2 = Math.Abs(c[k])+Math.Abs(a[k+1]);
+                if( k<n-1 )
+                {
+                    scale2 = scale2+Math.Abs(b[k+1]);
+                }
+                if( (double)(a[k])==(double)(0) )
+                {
+                    piv1 = 0;
+                }
+                else
+                {
+                    piv1 = Math.Abs(a[k])/scale1;
+                }
+                if( (double)(c[k])==(double)(0) )
+                {
+                    iin[k] = 0;
+                    piv2 = 0;
+                    scale1 = scale2;
+                    if( k<n-1 )
+                    {
+                        d[k] = 0;
+                    }
+                }
+                else
+                {
+                    piv2 = Math.Abs(c[k])/scale2;
+                    if( (double)(piv2)<=(double)(piv1) )
+                    {
+                        iin[k] = 0;
+                        scale1 = scale2;
+                        c[k] = c[k]/a[k];
+                        a[k+1] = a[k+1]-c[k]*b[k];
+                        if( k<n-1 )
+                        {
+                            d[k] = 0;
+                        }
+                    }
+                    else
+                    {
+                        iin[k] = 1;
+                        mult = a[k]/c[k];
+                        a[k] = c[k];
+                        temp = a[k+1];
+                        a[k+1] = b[k]-mult*temp;
+                        if( k<n-1 )
+                        {
+                            d[k] = b[k+1];
+                            b[k+1] = -(mult*d[k]);
+                        }
+                        b[k] = temp;
+                        c[k] = mult;
+                    }
+                }
+                if( (double)(Math.Max(piv1, piv2))<=(double)(tl) & iin[n]==0 )
+                {
+                    iin[n] = k;
+                }
+            }
+            if( (double)(Math.Abs(a[n]))<=(double)(scale1*tl) & iin[n]==0 )
+            {
+                iin[n] = n;
+            }
+        }
+
+
+        private static void tdininternaldlagts(int n,
+            ref double[] a,
+            ref double[] b,
+            ref double[] c,
+            ref double[] d,
+            ref int[] iin,
+            ref double[] y,
+            ref double tol,
+            ref int info)
+        {
+            int k = 0;
+            double absak = 0;
+            double ak = 0;
+            double bignum = 0;
+            double eps = 0;
+            double pert = 0;
+            double sfmin = 0;
+            double temp = 0;
+
+            info = 0;
+            if( n<0 )
+            {
+                info = -1;
+                return;
+            }
+            if( n==0 )
+            {
+                return;
+            }
+            eps = AP.Math.MachineEpsilon;
+            sfmin = AP.Math.MinRealNumber;
+            bignum = 1/sfmin;
+            if( (double)(tol)<=(double)(0) )
+            {
+                tol = Math.Abs(a[1]);
+                if( n>1 )
+                {
+                    tol = Math.Max(tol, Math.Max(Math.Abs(a[2]), Math.Abs(b[1])));
+                }
+                for(k=3; k<=n; k++)
+                {
+                    tol = Math.Max(tol, Math.Max(Math.Abs(a[k]), Math.Max(Math.Abs(b[k-1]), Math.Abs(d[k-2]))));
+                }
+                tol = tol*eps;
+                if( (double)(tol)==(double)(0) )
+                {
+                    tol = eps;
+                }
+            }
+            for(k=2; k<=n; k++)
+            {
+                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--)
+            {
+                if( k<=n-2 )
+                {
+                    temp = y[k]-b[k]*y[k+1]-d[k]*y[k+2];
+                }
+                else
+                {
+                    if( k==n-1 )
+                    {
+                        temp = y[k]-b[k]*y[k+1];
+                    }
+                    else
+                    {
+                        temp = y[k];
+                    }
+                }
+                ak = a[k];
+                pert = Math.Abs(tol);
+                if( (double)(ak)<(double)(0) )
+                {
+                    pert = -pert;
+                }
+                while( true )
+                {
+                    absak = Math.Abs(ak);
+                    if( (double)(absak)<(double)(1) )
+                    {
+                        if( (double)(absak)<(double)(sfmin) )
+                        {
+                            if( (double)(absak)==(double)(0) | (double)(Math.Abs(temp)*sfmin)>(double)(absak) )
+                            {
+                                ak = ak+pert;
+                                pert = 2*pert;
+                                continue;
+                            }
+                            else
+                            {
+                                temp = temp*bignum;
+                                ak = ak*bignum;
+                            }
+                        }
+                        else
+                        {
+                            if( (double)(Math.Abs(temp))>(double)(absak*bignum) )
+                            {
+                                ak = ak+pert;
+                                pert = 2*pert;
+                                continue;
+                            }
+                        }
+                    }
+                    break;
+                }
+                y[k] = temp/ak;
+            }
+        }
+
+
+        private static void internaldlaebz(int ijob,
+            int nitmax,
+            int n,
+            int mmax,
+            int minp,
+            double abstol,
+            double reltol,
+            double pivmin,
+            ref double[] d,
+            ref double[] e,
+            ref double[] e2,
+            ref int[] nval,
+            ref double[,] ab,
+            ref double[] c,
+            ref int mout,
+            ref int[,] nab,
+            ref double[] work,
+            ref int[] iwork,
+            ref int info)
+        {
+            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;
+
+            info = 0;
+            if( ijob<1 | ijob>3 )
+            {
+                info = -1;
+                return;
+            }
+            
+            //
+            // Initialize NAB
+            //
+            if( ijob==1 )
+            {
+                
+                //
+                // Compute the number of eigenvalues in the initial intervals.
+                //
+                mout = 0;
+                
+                //
+                //DIR$ NOVECTOR
+                //
+                for(ji=1; ji<=minp; ji++)
+                {
+                    for(jp=1; jp<=2; jp++)
+                    {
+                        tmp1 = d[1]-ab[ji,jp];
+                        if( (double)(Math.Abs(tmp1))<(double)(pivmin) )
+                        {
+                            tmp1 = -pivmin;
+                        }
+                        nab[ji,jp] = 0;
+                        if( (double)(tmp1)<=(double)(0) )
+                        {
+                            nab[ji,jp] = 1;
+                        }
+                        for(j=2; j<=n; j++)
+                        {
+                            tmp1 = d[j]-e2[j-1]/tmp1-ab[ji,jp];
+                            if( (double)(Math.Abs(tmp1))<(double)(pivmin) )
+                            {
+                                tmp1 = -pivmin;
+                            }
+                            if( (double)(tmp1)<=(double)(0) )
+                            {
+                                nab[ji,jp] = nab[ji,jp]+1;
+                            }
+                        }
+                    }
+                    mout = mout+nab[ji,2]-nab[ji,1];
+                }
+                return;
+            }
+            
+            //
+            // Initialize for loop
+            //
+            // KF and KL have the following meaning:
+            //   Intervals 1,...,KF-1 have converged.
+            //   Intervals KF,...,KL  still need to be refined.
+            //
+            kf = 1;
+            kl = minp;
+            
+            //
+            // If IJOB=2, initialize C.
+            // If IJOB=3, use the user-supplied starting point.
+            //
+            if( ijob==2 )
+            {
+                for(ji=1; ji<=minp; ji++)
+                {
+                    c[ji] = 0.5*(ab[ji,1]+ab[ji,2]);
+                }
+            }
+            
+            //
+            // Iteration loop
+            //
+            for(jit=1; jit<=nitmax; jit++)
+            {
+                
+                //
+                // Loop over intervals
+                //
+                //
+                // Serial Version of the loop
+                //
+                klnew = kl;
+                for(ji=kf; ji<=kl; ji++)
+                {
+                    
+                    //
+                    // Compute N(w), the number of eigenvalues less than w
+                    //
+                    tmp1 = c[ji];
+                    tmp2 = d[1]-tmp1;
+                    itmp1 = 0;
+                    if( (double)(tmp2)<=(double)(pivmin) )
+                    {
+                        itmp1 = 1;
+                        tmp2 = Math.Min(tmp2, -pivmin);
+                    }
+                    
+                    //
+                    // A series of compiler directives to defeat vectorization
+                    // for the next loop
+                    //
+                    //*$PL$ CMCHAR=' '
+                    //CDIR$          NEXTSCALAR
+                    //C$DIR          SCALAR
+                    //CDIR$          NEXT SCALAR
+                    //CVD$L          NOVECTOR
+                    //CDEC$          NOVECTOR
+                    //CVD$           NOVECTOR
+                    //*VDIR          NOVECTOR
+                    //*VOCL          LOOP,SCALAR
+                    //CIBM           PREFER SCALAR
+                    //*$PL$ CMCHAR='*'
+                    //
+                    for(j=2; j<=n; j++)
+                    {
+                        tmp2 = d[j]-e2[j-1]/tmp2-tmp1;
+                        if( (double)(tmp2)<=(double)(pivmin) )
+                        {
+                            itmp1 = itmp1+1;
+                            tmp2 = Math.Min(tmp2, -pivmin);
+                        }
+                    }
+                    if( ijob<=2 )
+                    {
+                        
+                        //
+                        // IJOB=2: Choose all intervals containing eigenvalues.
+                        //
+                        // Insure that N(w) is monotone
+                        //
+                        itmp1 = Math.Min(nab[ji,2], Math.Max(nab[ji,1], itmp1));
+                        
+                        //
+                        // Update the Queue -- add intervals if both halves
+                        // contain eigenvalues.
+                        //
+                        if( itmp1==nab[ji,2] )
+                        {
+                            
+                            //
+                            // No eigenvalue in the upper interval:
+                            // just use the lower interval.
+                            //
+                            ab[ji,2] = tmp1;
+                        }
+                        else
+                        {
+                            if( itmp1==nab[ji,1] )
+                            {
+                                
+                                //
+                                // No eigenvalue in the lower interval:
+                                // just use the upper interval.
+                                //
+                                ab[ji,1] = tmp1;
+                            }
+                            else
+                            {
+                                if( klnew<mmax )
+                                {
+                                    
+                                    //
+                                    // Eigenvalue in both intervals -- add upper to queue.
+                                    //
+                                    klnew = klnew+1;
+                                    ab[klnew,2] = ab[ji,2];
+                                    nab[klnew,2] = nab[ji,2];
+                                    ab[klnew,1] = tmp1;
+                                    nab[klnew,1] = itmp1;
+                                    ab[ji,2] = tmp1;
+                                    nab[ji,2] = itmp1;
+                                }
+                                else
+                                {
+                                    info = mmax+1;
+                                    return;
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        
+                        //
+                        // IJOB=3: Binary search.  Keep only the interval
+                        // containing  w  s.t. N(w) = NVAL
+                        //
+                        if( itmp1<=nval[ji] )
+                        {
+                            ab[ji,1] = tmp1;
+                            nab[ji,1] = itmp1;
+                        }
+                        if( itmp1>=nval[ji] )
+                        {
+                            ab[ji,2] = tmp1;
+                            nab[ji,2] = itmp1;
+                        }
+                    }
+                }
+                kl = klnew;
+                
+                //
+                // Check for convergence
+                //
+                kfnew = kf;
+                for(ji=kf; ji<=kl; ji++)
+                {
+                    tmp1 = Math.Abs(ab[ji,2]-ab[ji,1]);
+                    tmp2 = Math.Max(Math.Abs(ab[ji,2]), Math.Abs(ab[ji,1]));
+                    if( (double)(tmp1)<(double)(Math.Max(abstol, Math.Max(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];
+                            ab[ji,1] = ab[kfnew,1];
+                            ab[ji,2] = ab[kfnew,2];
+                            nab[ji,1] = nab[kfnew,1];
+                            nab[ji,2] = nab[kfnew,2];
+                            ab[kfnew,1] = tmp1;
+                            ab[kfnew,2] = tmp2;
+                            nab[kfnew,1] = itmp1;
+                            nab[kfnew,2] = itmp2;
+                            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 = Math.Max(kl+1-kf, 0);
+            mout = kl;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tdevd.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tdevd.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tdevd.cs	(revision 2645)
@@ -0,0 +1,1280 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class tdevd
+    {
+        /*************************************************************************
+        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 hasnt changed;
+                         * 1, Z contains the product of a given matrix (from the left)
+                           and the eigenvectors matrix (from the right);
+                         * 2, Z contains the eigenvectors.
+                         * 3, Z contains the first row of the eigenvectors matrix.
+                        If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1].
+                        In that case, the eigenvectors are stored in the matrix columns.
+                        If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1].
+
+        Result:
+            True, if the algorithm has converged.
+            False, if the algorithm hasn't converged.
+
+          -- LAPACK routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             September 30, 1994
+        *************************************************************************/
+        public static bool smatrixtdevd(ref double[] d,
+            double[] e,
+            int n,
+            int zneeded,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            double[] d1 = new double[0];
+            double[] e1 = new double[0];
+            double[,] z1 = new double[0,0];
+            int i = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            e = (double[])e.Clone();
+
+            
+            //
+            // Prepare 1-based task
+            //
+            d1 = new double[n+1];
+            e1 = new double[n+1];
+            i1_ = (0) - (1);
+            for(i_=1; i_<=n;i_++)
+            {
+                d1[i_] = d[i_+i1_];
+            }
+            if( n>1 )
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n-1;i_++)
+                {
+                    e1[i_] = e[i_+i1_];
+                }
+            }
+            if( zneeded==1 )
+            {
+                z1 = new double[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    i1_ = (0) - (1);
+                    for(i_=1; i_<=n;i_++)
+                    {
+                        z1[i,i_] = z[i-1,i_+i1_];
+                    }
+                }
+            }
+            
+            //
+            // Solve 1-based task
+            //
+            result = tridiagonalevd(ref d1, e1, n, zneeded, ref z1);
+            if( !result )
+            {
+                return result;
+            }
+            
+            //
+            // Convert back to 0-based result
+            //
+            i1_ = (1) - (0);
+            for(i_=0; i_<=n-1;i_++)
+            {
+                d[i_] = d1[i_+i1_];
+            }
+            if( zneeded!=0 )
+            {
+                if( zneeded==1 )
+                {
+                    for(i=1; i<=n; i++)
+                    {
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            z[i-1,i_] = z1[i,i_+i1_];
+                        }
+                    }
+                    return result;
+                }
+                if( zneeded==2 )
+                {
+                    z = new double[n-1+1, n-1+1];
+                    for(i=1; i<=n; i++)
+                    {
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=n-1;i_++)
+                        {
+                            z[i-1,i_] = z1[i,i_+i1_];
+                        }
+                    }
+                    return result;
+                }
+                if( zneeded==3 )
+                {
+                    z = new double[0+1, n-1+1];
+                    i1_ = (1) - (0);
+                    for(i_=0; i_<=n-1;i_++)
+                    {
+                        z[0,i_] = z1[1,i_+i1_];
+                    }
+                    return result;
+                }
+                System.Diagnostics.Debug.Assert(false, "SMatrixTDEVD: Incorrect ZNeeded!");
+            }
+            return result;
+        }
+
+
+        public static bool tridiagonalevd(ref double[] d,
+            double[] e,
+            int n,
+            int zneeded,
+            ref double[,] z)
+        {
+            bool result = new bool();
+            int maxit = 0;
+            int i = 0;
+            int icompz = 0;
+            int ii = 0;
+            int iscale = 0;
+            int j = 0;
+            int jtot = 0;
+            int k = 0;
+            int t = 0;
+            int l = 0;
+            int l1 = 0;
+            int lend = 0;
+            int lendm1 = 0;
+            int lendp1 = 0;
+            int lendsv = 0;
+            int lm1 = 0;
+            int lsv = 0;
+            int m = 0;
+            int mm = 0;
+            int mm1 = 0;
+            int nm1 = 0;
+            int nmaxit = 0;
+            int tmpint = 0;
+            double anorm = 0;
+            double b = 0;
+            double c = 0;
+            double eps = 0;
+            double eps2 = 0;
+            double f = 0;
+            double g = 0;
+            double p = 0;
+            double r = 0;
+            double rt1 = 0;
+            double rt2 = 0;
+            double s = 0;
+            double safmax = 0;
+            double safmin = 0;
+            double ssfmax = 0;
+            double ssfmin = 0;
+            double tst = 0;
+            double tmp = 0;
+            double[] work1 = new double[0];
+            double[] work2 = new double[0];
+            double[] workc = new double[0];
+            double[] works = new double[0];
+            double[] wtemp = new double[0];
+            bool gotoflag = new bool();
+            int zrows = 0;
+            bool wastranspose = new bool();
+            int i_ = 0;
+
+            e = (double[])e.Clone();
+
+            System.Diagnostics.Debug.Assert(zneeded>=0 & zneeded<=3, "TridiagonalEVD: Incorrent ZNeeded");
+            
+            //
+            // Quick return if possible
+            //
+            if( zneeded<0 | zneeded>3 )
+            {
+                result = false;
+                return result;
+            }
+            result = true;
+            if( n==0 )
+            {
+                return result;
+            }
+            if( n==1 )
+            {
+                if( zneeded==2 | zneeded==3 )
+                {
+                    z = new double[1+1, 1+1];
+                    z[1,1] = 1;
+                }
+                return result;
+            }
+            maxit = 30;
+            
+            //
+            // Initialize arrays
+            //
+            wtemp = new double[n+1];
+            work1 = new double[n-1+1];
+            work2 = new double[n-1+1];
+            workc = new double[n+1];
+            works = new double[n+1];
+            
+            //
+            // Determine the unit roundoff and over/underflow thresholds.
+            //
+            eps = AP.Math.MachineEpsilon;
+            eps2 = AP.Math.Sqr(eps);
+            safmin = AP.Math.MinRealNumber;
+            safmax = AP.Math.MaxRealNumber;
+            ssfmax = Math.Sqrt(safmax)/3;
+            ssfmin = Math.Sqrt(safmin)/eps2;
+            
+            //
+            // Prepare Z
+            //
+            // Here we are using transposition to get rid of column operations
+            //
+            //
+            wastranspose = false;
+            if( zneeded==0 )
+            {
+                zrows = 0;
+            }
+            if( zneeded==1 )
+            {
+                zrows = n;
+            }
+            if( zneeded==2 )
+            {
+                zrows = n;
+            }
+            if( zneeded==3 )
+            {
+                zrows = 1;
+            }
+            if( zneeded==1 )
+            {
+                wastranspose = true;
+                blas.inplacetranspose(ref z, 1, n, 1, n, ref wtemp);
+            }
+            if( zneeded==2 )
+            {
+                wastranspose = true;
+                z = new double[n+1, n+1];
+                for(i=1; i<=n; i++)
+                {
+                    for(j=1; j<=n; j++)
+                    {
+                        if( i==j )
+                        {
+                            z[i,j] = 1;
+                        }
+                        else
+                        {
+                            z[i,j] = 0;
+                        }
+                    }
+                }
+            }
+            if( zneeded==3 )
+            {
+                wastranspose = false;
+                z = new double[1+1, n+1];
+                for(j=1; j<=n; j++)
+                {
+                    if( j==1 )
+                    {
+                        z[1,j] = 1;
+                    }
+                    else
+                    {
+                        z[1,j] = 0;
+                    }
+                }
+            }
+            nmaxit = n*maxit;
+            jtot = 0;
+            
+            //
+            // Determine where the matrix splits and choose QL or QR iteration
+            // for each block, according to whether top or bottom diagonal
+            // element is smaller.
+            //
+            l1 = 1;
+            nm1 = n-1;
+            while( true )
+            {
+                if( l1>n )
+                {
+                    break;
+                }
+                if( l1>1 )
+                {
+                    e[l1-1] = 0;
+                }
+                gotoflag = false;
+                if( l1<=nm1 )
+                {
+                    for(m=l1; m<=nm1; m++)
+                    {
+                        tst = Math.Abs(e[m]);
+                        if( (double)(tst)==(double)(0) )
+                        {
+                            gotoflag = true;
+                            break;
+                        }
+                        if( (double)(tst)<=(double)(Math.Sqrt(Math.Abs(d[m]))*Math.Sqrt(Math.Abs(d[m+1]))*eps) )
+                        {
+                            e[m] = 0;
+                            gotoflag = true;
+                            break;
+                        }
+                    }
+                }
+                if( !gotoflag )
+                {
+                    m = n;
+                }
+                
+                //
+                // label 30:
+                //
+                l = l1;
+                lsv = l;
+                lend = m;
+                lendsv = lend;
+                l1 = m+1;
+                if( lend==l )
+                {
+                    continue;
+                }
+                
+                //
+                // Scale submatrix in rows and columns L to LEND
+                //
+                if( l==lend )
+                {
+                    anorm = Math.Abs(d[l]);
+                }
+                else
+                {
+                    anorm = Math.Max(Math.Abs(d[l])+Math.Abs(e[l]), Math.Abs(e[lend-1])+Math.Abs(d[lend]));
+                    for(i=l+1; i<=lend-1; i++)
+                    {
+                        anorm = Math.Max(anorm, Math.Abs(d[i])+Math.Abs(e[i])+Math.Abs(e[i-1]));
+                    }
+                }
+                iscale = 0;
+                if( (double)(anorm)==(double)(0) )
+                {
+                    continue;
+                }
+                if( (double)(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_];
+                    }
+                }
+                if( (double)(anorm)<(double)(ssfmin) )
+                {
+                    iscale = 2;
+                    tmp = ssfmin/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_];
+                    }
+                }
+                
+                //
+                // Choose between QL and QR iteration
+                //
+                if( (double)(Math.Abs(d[lend]))<(double)(Math.Abs(d[l])) )
+                {
+                    lend = lsv;
+                    l = lendsv;
+                }
+                if( lend>l )
+                {
+                    
+                    //
+                    // QL Iteration
+                    //
+                    // Look for small subdiagonal element.
+                    //
+                    while( true )
+                    {
+                        gotoflag = false;
+                        if( l!=lend )
+                        {
+                            lendm1 = lend-1;
+                            for(m=l; m<=lendm1; m++)
+                            {
+                                tst = AP.Math.Sqr(Math.Abs(e[m]));
+                                if( (double)(tst)<=(double)(eps2*Math.Abs(d[m])*Math.Abs(d[m+1])+safmin) )
+                                {
+                                    gotoflag = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if( !gotoflag )
+                        {
+                            m = lend;
+                        }
+                        if( m<lend )
+                        {
+                            e[m] = 0;
+                        }
+                        p = d[l];
+                        if( m!=l )
+                        {
+                            
+                            //
+                            // If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
+                            // to compute its eigensystem.
+                            //
+                            if( m==l+1 )
+                            {
+                                if( zneeded>0 )
+                                {
+                                    tdevdev2(d[l], e[l], d[l+1], ref rt1, ref rt2, ref c, ref s);
+                                    work1[l] = c;
+                                    work2[l] = s;
+                                    workc[1] = work1[l];
+                                    works[1] = work2[l];
+                                    if( !wastranspose )
+                                    {
+                                        rotations.applyrotationsfromtheright(false, 1, zrows, l, l+1, ref workc, ref works, ref z, ref wtemp);
+                                    }
+                                    else
+                                    {
+                                        rotations.applyrotationsfromtheleft(false, l, l+1, 1, zrows, ref workc, ref works, ref z, ref wtemp);
+                                    }
+                                }
+                                else
+                                {
+                                    tdevde2(d[l], e[l], d[l+1], ref rt1, ref rt2);
+                                }
+                                d[l] = rt1;
+                                d[l+1] = rt2;
+                                e[l] = 0;
+                                l = l+2;
+                                if( l<=lend )
+                                {
+                                    continue;
+                                }
+                                
+                                //
+                                // GOTO 140
+                                //
+                                break;
+                            }
+                            if( jtot==nmaxit )
+                            {
+                                
+                                //
+                                // GOTO 140
+                                //
+                                break;
+                            }
+                            jtot = jtot+1;
+                            
+                            //
+                            // Form shift.
+                            //
+                            g = (d[l+1]-p)/(2*e[l]);
+                            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];
+                                rotations.generaterotation(g, f, ref c, ref s, ref r);
+                                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<=m-1; i++)
+                                {
+                                    workc[i-l+1] = work1[i];
+                                    works[i-l+1] = work2[i];
+                                }
+                                if( !wastranspose )
+                                {
+                                    rotations.applyrotationsfromtheright(false, 1, zrows, l, m, ref workc, ref works, ref z, ref wtemp);
+                                }
+                                else
+                                {
+                                    rotations.applyrotationsfromtheleft(false, l, m, 1, zrows, ref workc, ref works, ref z, ref wtemp);
+                                }
+                            }
+                            d[l] = d[l]-p;
+                            e[l] = g;
+                            continue;
+                        }
+                        
+                        //
+                        // Eigenvalue found.
+                        //
+                        d[l] = p;
+                        l = l+1;
+                        if( l<=lend )
+                        {
+                            continue;
+                        }
+                        break;
+                    }
+                }
+                else
+                {
+                    
+                    //
+                    // QR Iteration
+                    //
+                    // Look for small superdiagonal element.
+                    //
+                    while( true )
+                    {
+                        gotoflag = false;
+                        if( l!=lend )
+                        {
+                            lendp1 = lend+1;
+                            for(m=l; m>=lendp1; m--)
+                            {
+                                tst = AP.Math.Sqr(Math.Abs(e[m-1]));
+                                if( (double)(tst)<=(double)(eps2*Math.Abs(d[m])*Math.Abs(d[m-1])+safmin) )
+                                {
+                                    gotoflag = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if( !gotoflag )
+                        {
+                            m = lend;
+                        }
+                        if( m>lend )
+                        {
+                            e[m-1] = 0;
+                        }
+                        p = d[l];
+                        if( m!=l )
+                        {
+                            
+                            //
+                            // If remaining matrix is 2-by-2, use DLAE2 or SLAEV2
+                            // to compute its eigensystem.
+                            //
+                            if( m==l-1 )
+                            {
+                                if( zneeded>0 )
+                                {
+                                    tdevdev2(d[l-1], e[l-1], d[l], ref rt1, ref rt2, ref c, ref s);
+                                    work1[m] = c;
+                                    work2[m] = s;
+                                    workc[1] = c;
+                                    works[1] = s;
+                                    if( !wastranspose )
+                                    {
+                                        rotations.applyrotationsfromtheright(true, 1, zrows, l-1, l, ref workc, ref works, ref z, ref wtemp);
+                                    }
+                                    else
+                                    {
+                                        rotations.applyrotationsfromtheleft(true, l-1, l, 1, zrows, ref workc, ref works, ref z, ref wtemp);
+                                    }
+                                }
+                                else
+                                {
+                                    tdevde2(d[l-1], e[l-1], d[l], ref rt1, ref rt2);
+                                }
+                                d[l-1] = rt1;
+                                d[l] = rt2;
+                                e[l-1] = 0;
+                                l = l-2;
+                                if( l>=lend )
+                                {
+                                    continue;
+                                }
+                                break;
+                            }
+                            if( jtot==nmaxit )
+                            {
+                                break;
+                            }
+                            jtot = jtot+1;
+                            
+                            //
+                            // Form shift.
+                            //
+                            g = (d[l-1]-p)/(2*e[l-1]);
+                            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];
+                                rotations.generaterotation(g, f, ref c, ref s, ref r);
+                                if( i!=m )
+                                {
+                                    e[i-1] = r;
+                                }
+                                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];
+                                }
+                                if( !wastranspose )
+                                {
+                                    rotations.applyrotationsfromtheright(true, 1, zrows, m, l, ref workc, ref works, ref z, ref wtemp);
+                                }
+                                else
+                                {
+                                    rotations.applyrotationsfromtheleft(true, m, l, 1, zrows, ref workc, ref works, ref z, ref wtemp);
+                                }
+                            }
+                            d[l] = d[l]-p;
+                            e[lm1] = g;
+                            continue;
+                        }
+                        
+                        //
+                        // Eigenvalue found.
+                        //
+                        d[l] = p;
+                        l = l-1;
+                        if( l>=lend )
+                        {
+                            continue;
+                        }
+                        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_];
+                    }
+                }
+                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;
+                    if( wastranspose )
+                    {
+                        blas.inplacetranspose(ref z, 1, n, 1, n, ref wtemp);
+                    }
+                    return result;
+                }
+            }
+            
+            //
+            // Order eigenvalues and eigenvectors.
+            //
+            if( zneeded==0 )
+            {
+                
+                //
+                // Sort
+                //
+                if( n==1 )
+                {
+                    return result;
+                }
+                if( n==2 )
+                {
+                    if( (double)(d[1])>(double)(d[2]) )
+                    {
+                        tmp = d[1];
+                        d[1] = d[2];
+                        d[2] = tmp;
+                    }
+                    return result;
+                }
+                i = 2;
+                do
+                {
+                    t = i;
+                    while( t!=1 )
+                    {
+                        k = t/2;
+                        if( (double)(d[k])>=(double)(d[t]) )
+                        {
+                            t = 1;
+                        }
+                        else
+                        {
+                            tmp = d[k];
+                            d[k] = d[t];
+                            d[t] = tmp;
+                            t = k;
+                        }
+                    }
+                    i = i+1;
+                }
+                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;
+                        if( k>i )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            if( k<i )
+                            {
+                                if( (double)(d[k+1])>(double)(d[k]) )
+                                {
+                                    k = k+1;
+                                }
+                            }
+                            if( (double)(d[t])>=(double)(d[k]) )
+                            {
+                                t = 0;
+                            }
+                            else
+                            {
+                                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++)
+                    {
+                        if( (double)(d[j])<(double)(p) )
+                        {
+                            k = j;
+                            p = d[j];
+                        }
+                    }
+                    if( k!=i )
+                    {
+                        d[k] = d[i];
+                        d[i] = p;
+                        if( wastranspose )
+                        {
+                            for(i_=1; i_<=n;i_++)
+                            {
+                                wtemp[i_] = z[i,i_];
+                            }
+                            for(i_=1; i_<=n;i_++)
+                            {
+                                z[i,i_] = z[k,i_];
+                            }
+                            for(i_=1; i_<=n;i_++)
+                            {
+                                z[k,i_] = wtemp[i_];
+                            }
+                        }
+                        else
+                        {
+                            for(i_=1; i_<=zrows;i_++)
+                            {
+                                wtemp[i_] = z[i_,i];
+                            }
+                            for(i_=1; i_<=zrows;i_++)
+                            {
+                                z[i_,i] = z[i_,k];
+                            }
+                            for(i_=1; i_<=zrows;i_++)
+                            {
+                                z[i_,k] = wtemp[i_];
+                            }
+                        }
+                    }
+                }
+                if( wastranspose )
+                {
+                    blas.inplacetranspose(ref z, 1, n, 1, n, ref wtemp);
+                }
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        DLAE2  computes the eigenvalues of a 2-by-2 symmetric matrix
+           [  A   B  ]
+           [  B   C  ].
+        On return, RT1 is the eigenvalue of larger absolute value, and RT2
+        is the eigenvalue of smaller absolute value.
+
+          -- LAPACK auxiliary routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             October 31, 1992
+        *************************************************************************/
+        private static void tdevde2(double a,
+            double b,
+            double c,
+            ref double rt1,
+            ref double rt2)
+        {
+            double ab = 0;
+            double acmn = 0;
+            double acmx = 0;
+            double adf = 0;
+            double df = 0;
+            double rt = 0;
+            double sm = 0;
+            double tb = 0;
+
+            sm = a+c;
+            df = a-c;
+            adf = Math.Abs(df);
+            tb = b+b;
+            ab = Math.Abs(tb);
+            if( (double)(Math.Abs(a))>(double)(Math.Abs(c)) )
+            {
+                acmx = a;
+                acmn = c;
+            }
+            else
+            {
+                acmx = c;
+                acmn = a;
+            }
+            if( (double)(adf)>(double)(ab) )
+            {
+                rt = adf*Math.Sqrt(1+AP.Math.Sqr(ab/adf));
+            }
+            else
+            {
+                if( (double)(adf)<(double)(ab) )
+                {
+                    rt = ab*Math.Sqrt(1+AP.Math.Sqr(adf/ab));
+                }
+                else
+                {
+                    
+                    //
+                    // Includes case AB=ADF=0
+                    //
+                    rt = ab*Math.Sqrt(2);
+                }
+            }
+            if( (double)(sm)<(double)(0) )
+            {
+                rt1 = 0.5*(sm-rt);
+                
+                //
+                // Order of execution important.
+                // To get fully accurate smaller eigenvalue,
+                // next line needs to be executed in higher precision.
+                //
+                rt2 = acmx/rt1*acmn-b/rt1*b;
+            }
+            else
+            {
+                if( (double)(sm)>(double)(0) )
+                {
+                    rt1 = 0.5*(sm+rt);
+                    
+                    //
+                    // Order of execution important.
+                    // To get fully accurate smaller eigenvalue,
+                    // next line needs to be executed in higher precision.
+                    //
+                    rt2 = acmx/rt1*acmn-b/rt1*b;
+                }
+                else
+                {
+                    
+                    //
+                    // Includes case RT1 = RT2 = 0
+                    //
+                    rt1 = 0.5*rt;
+                    rt2 = -(0.5*rt);
+                }
+            }
+        }
+
+
+        /*************************************************************************
+        DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix
+
+           [  A   B  ]
+           [  B   C  ].
+
+        On return, RT1 is the eigenvalue of larger absolute value, RT2 is the
+        eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right
+        eigenvector for RT1, giving the decomposition
+
+           [ CS1  SN1 ] [  A   B  ] [ CS1 -SN1 ]  =  [ RT1  0  ]
+           [-SN1  CS1 ] [  B   C  ] [ SN1  CS1 ]     [  0  RT2 ].
+
+
+          -- LAPACK auxiliary routine (version 3.0) --
+             Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+             Courant Institute, Argonne National Lab, and Rice University
+             October 31, 1992
+        *************************************************************************/
+        private static void tdevdev2(double a,
+            double b,
+            double c,
+            ref double rt1,
+            ref double rt2,
+            ref double cs1,
+            ref double sn1)
+        {
+            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;
+
+            
+            //
+            // Compute the eigenvalues
+            //
+            sm = a+c;
+            df = a-c;
+            adf = Math.Abs(df);
+            tb = b+b;
+            ab = Math.Abs(tb);
+            if( (double)(Math.Abs(a))>(double)(Math.Abs(c)) )
+            {
+                acmx = a;
+                acmn = c;
+            }
+            else
+            {
+                acmx = c;
+                acmn = a;
+            }
+            if( (double)(adf)>(double)(ab) )
+            {
+                rt = adf*Math.Sqrt(1+AP.Math.Sqr(ab/adf));
+            }
+            else
+            {
+                if( (double)(adf)<(double)(ab) )
+                {
+                    rt = ab*Math.Sqrt(1+AP.Math.Sqr(adf/ab));
+                }
+                else
+                {
+                    
+                    //
+                    // Includes case AB=ADF=0
+                    //
+                    rt = ab*Math.Sqrt(2);
+                }
+            }
+            if( (double)(sm)<(double)(0) )
+            {
+                rt1 = 0.5*(sm-rt);
+                sgn1 = -1;
+                
+                //
+                // Order of execution important.
+                // To get fully accurate smaller eigenvalue,
+                // next line needs to be executed in higher precision.
+                //
+                rt2 = acmx/rt1*acmn-b/rt1*b;
+            }
+            else
+            {
+                if( (double)(sm)>(double)(0) )
+                {
+                    rt1 = 0.5*(sm+rt);
+                    sgn1 = 1;
+                    
+                    //
+                    // Order of execution important.
+                    // To get fully accurate smaller eigenvalue,
+                    // next line needs to be executed in higher precision.
+                    //
+                    rt2 = acmx/rt1*acmn-b/rt1*b;
+                }
+                else
+                {
+                    
+                    //
+                    // Includes case RT1 = RT2 = 0
+                    //
+                    rt1 = 0.5*rt;
+                    rt2 = -(0.5*rt);
+                    sgn1 = 1;
+                }
+            }
+            
+            //
+            // Compute the eigenvector
+            //
+            if( (double)(df)>=(double)(0) )
+            {
+                cs = df+rt;
+                sgn2 = 1;
+            }
+            else
+            {
+                cs = df-rt;
+                sgn2 = -1;
+            }
+            acs = Math.Abs(cs);
+            if( (double)(acs)>(double)(ab) )
+            {
+                ct = -(tb/cs);
+                sn1 = 1/Math.Sqrt(1+ct*ct);
+                cs1 = ct*sn1;
+            }
+            else
+            {
+                if( (double)(ab)==(double)(0) )
+                {
+                    cs1 = 1;
+                    sn1 = 0;
+                }
+                else
+                {
+                    tn = -(cs/tb);
+                    cs1 = 1/Math.Sqrt(1+tn*tn);
+                    sn1 = tn*cs1;
+                }
+            }
+            if( sgn1==sgn2 )
+            {
+                tn = cs1;
+                cs1 = -sn1;
+                sn1 = tn;
+            }
+        }
+
+
+        /*************************************************************************
+        Internal routine
+        *************************************************************************/
+        private static double tdevdpythag(double a,
+            double b)
+        {
+            double result = 0;
+
+            if( (double)(Math.Abs(a))<(double)(Math.Abs(b)) )
+            {
+                result = Math.Abs(b)*Math.Sqrt(1+AP.Math.Sqr(a/b));
+            }
+            else
+            {
+                result = Math.Abs(a)*Math.Sqrt(1+AP.Math.Sqr(b/a));
+            }
+            return result;
+        }
+
+
+        /*************************************************************************
+        Internal routine
+        *************************************************************************/
+        private static double tdevdextsign(double a,
+            double b)
+        {
+            double result = 0;
+
+            if( (double)(b)>=(double)(0) )
+            {
+                result = Math.Abs(a);
+            }
+            else
+            {
+                result = -Math.Abs(a);
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tridiagonal.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tridiagonal.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tridiagonal.cs	(revision 2645)
@@ -0,0 +1,719 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class tridiagonal
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static void smatrixtd(ref double[,] a,
+            int n,
+            bool isupper,
+            ref double[] tau,
+            ref double[] d,
+            ref double[] e)
+        {
+            int i = 0;
+            double alpha = 0;
+            double taui = 0;
+            double v = 0;
+            double[] t = new double[0];
+            double[] t2 = new double[0];
+            double[] t3 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n<=0 )
+            {
+                return;
+            }
+            t = new double[n+1];
+            t2 = new double[n+1];
+            t3 = new double[n+1];
+            if( n>1 )
+            {
+                tau = new double[n-2+1];
+            }
+            d = new double[n-1+1];
+            if( n>1 )
+            {
+                e = new double[n-2+1];
+            }
+            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_ = (0) - (2);
+                        for(i_=2; i_<=i+1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                    }
+                    t[1] = a[i,i+1];
+                    reflections.generatereflection(ref t, i+1, ref taui);
+                    if( i>=1 )
+                    {
+                        i1_ = (2) - (0);
+                        for(i_=0; i_<=i-1;i_++)
+                        {
+                            a[i_,i+1] = t[i_+i1_];
+                        }
+                    }
+                    a[i,i+1] = t[1];
+                    e[i] = a[i,i+1];
+                    if( (double)(taui)!=(double)(0) )
+                    {
+                        
+                        //
+                        // Apply H from both sides to A
+                        //
+                        a[i,i+1] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing x in TAU
+                        //
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=i+1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                        sblas.symmetricmatrixvectormultiply(ref a, isupper, 0, i, ref t, taui, ref t3);
+                        i1_ = (1) - (0);
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            tau[i_] = t3[i_+i1_];
+                        }
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        v = 0.0;
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            v += tau[i_]*a[i_,i+1];
+                        }
+                        alpha = -(0.5*taui*v);
+                        for(i_=0; i_<=i;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_,i+1];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        //    A := A - v * w' - w * v'
+                        //
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=i+1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i+1];
+                        }
+                        i1_ = (0) - (1);
+                        for(i_=1; i_<=i+1;i_++)
+                        {
+                            t3[i_] = tau[i_+i1_];
+                        }
+                        sblas.symmetricrank2update(ref a, isupper, 0, i, ref t, ref t3, ref t2, -1);
+                        a[i,i+1] = e[i];
+                    }
+                    d[i+1] = a[i+1,i+1];
+                    tau[i] = taui;
+                }
+                d[0] = a[0,0];
+            }
+            else
+            {
+                
+                //
+                // Reduce the lower triangle of A
+                //
+                for(i=0; i<=n-2; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector H = E - tau * v * v'
+                    //
+                    i1_ = (i+1) - (1);
+                    for(i_=1; i_<=n-i-1;i_++)
+                    {
+                        t[i_] = a[i_+i1_,i];
+                    }
+                    reflections.generatereflection(ref t, n-i-1, ref taui);
+                    i1_ = (1) - (i+1);
+                    for(i_=i+1; i_<=n-1;i_++)
+                    {
+                        a[i_,i] = t[i_+i1_];
+                    }
+                    e[i] = a[i+1,i];
+                    if( (double)(taui)!=(double)(0) )
+                    {
+                        
+                        //
+                        // Apply H from both sides to A
+                        //
+                        a[i+1,i] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing y in TAU
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        sblas.symmetricmatrixvectormultiply(ref a, isupper, i+1, n-1, ref t, taui, ref t2);
+                        i1_ = (1) - (i);
+                        for(i_=i; i_<=n-2;i_++)
+                        {
+                            tau[i_] = t2[i_+i1_];
+                        }
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        i1_ = (i+1)-(i);
+                        v = 0.0;
+                        for(i_=i; i_<=n-2;i_++)
+                        {
+                            v += tau[i_]*a[i_+i1_,i];
+                        }
+                        alpha = -(0.5*taui*v);
+                        i1_ = (i+1) - (i);
+                        for(i_=i; i_<=n-2;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_+i1_,i];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        //     A := A - v * w' - w * v'
+                        //
+                        //
+                        i1_ = (i+1) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=n-i-1;i_++)
+                        {
+                            t2[i_] = tau[i_+i1_];
+                        }
+                        sblas.symmetricrank2update(ref a, isupper, i+1, n-1, ref t, ref t2, ref t3, -1);
+                        a[i+1,i] = e[i];
+                    }
+                    d[i] = a[i,i];
+                    tau[i] = taui;
+                }
+                d[n-1] = a[n-1,n-1];
+            }
+        }
+
+
+        /*************************************************************************
+        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].
+
+          -- ALGLIB --
+             Copyright 2005-2008 by Bochkanov Sergey
+        *************************************************************************/
+        public static void smatrixtdunpackq(ref double[,] a,
+            int n,
+            bool isupper,
+            ref double[] tau,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new double[n-1+1, n-1+1];
+            v = new double[n+1];
+            work = new double[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                for(j=0; j<=n-1; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            if( isupper )
+            {
+                for(i=0; i<=n-2; i++)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    i1_ = (0) - (1);
+                    for(i_=1; i_<=i+1;i_++)
+                    {
+                        v[i_] = a[i_+i1_,i+1];
+                    }
+                    v[i+1] = 1;
+                    reflections.applyreflectionfromtheleft(ref q, tau[i], ref v, 0, i, 0, n-1, ref work);
+                }
+            }
+            else
+            {
+                for(i=n-2; i>=0; i--)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    i1_ = (i+1) - (1);
+                    for(i_=1; i_<=n-i-1;i_++)
+                    {
+                        v[i_] = a[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    reflections.applyreflectionfromtheleft(ref q, tau[i], ref v, i+1, n-1, 0, n-1, ref work);
+                }
+            }
+        }
+
+
+        public static void totridiagonal(ref double[,] a,
+            int n,
+            bool isupper,
+            ref double[] tau,
+            ref double[] d,
+            ref double[] e)
+        {
+            int i = 0;
+            int ip1 = 0;
+            int im1 = 0;
+            int nmi = 0;
+            int nm1 = 0;
+            double alpha = 0;
+            double taui = 0;
+            double v = 0;
+            double[] t = new double[0];
+            double[] t2 = new double[0];
+            double[] t3 = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n<=0 )
+            {
+                return;
+            }
+            t = new double[n+1];
+            t2 = new double[n+1];
+            t3 = new double[n+1];
+            tau = new double[Math.Max(1, n-1)+1];
+            d = new double[n+1];
+            e = new double[Math.Max(1, n-1)+1];
+            if( isupper )
+            {
+                
+                //
+                // Reduce the upper triangle of A
+                //
+                for(i=n-1; i>=1; i--)
+                {
+                    
+                    //
+                    // Generate elementary reflector H(i) = I - tau * v * v'
+                    // to annihilate A(1:i-1,i+1)
+                    //
+                    // DLARFG( I, A( I, I+1 ), A( 1, I+1 ), 1, TAUI );
+                    //
+                    ip1 = i+1;
+                    im1 = i-1;
+                    if( i>=2 )
+                    {
+                        i1_ = (1) - (2);
+                        for(i_=2; i_<=i;i_++)
+                        {
+                            t[i_] = a[i_+i1_,ip1];
+                        }
+                    }
+                    t[1] = a[i,ip1];
+                    reflections.generatereflection(ref t, i, ref taui);
+                    if( i>=2 )
+                    {
+                        i1_ = (2) - (1);
+                        for(i_=1; i_<=im1;i_++)
+                        {
+                            a[i_,ip1] = t[i_+i1_];
+                        }
+                    }
+                    a[i,ip1] = t[1];
+                    e[i] = a[i,i+1];
+                    if( (double)(taui)!=(double)(0) )
+                    {
+                        
+                        //
+                        // Apply H(i) from both sides to A(1:i,1:i)
+                        //
+                        a[i,i+1] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing x in TAU(1:i)
+                        //
+                        // DSYMV( UPLO, I, TAUI, A, LDA, A( 1, I+1 ), 1, ZERO, TAU, 1 );
+                        //
+                        ip1 = i+1;
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            t[i_] = a[i_,ip1];
+                        }
+                        sblas.symmetricmatrixvectormultiply(ref a, isupper, 1, i, ref t, taui, ref tau);
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        ip1 = i+1;
+                        v = 0.0;
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            v += tau[i_]*a[i_,ip1];
+                        }
+                        alpha = -(0.5*taui*v);
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_,ip1];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        //    A := A - v * w' - w * v'
+                        //
+                        // DSYR2( UPLO, I, -ONE, A( 1, I+1 ), 1, TAU, 1, A, LDA );
+                        //
+                        for(i_=1; i_<=i;i_++)
+                        {
+                            t[i_] = a[i_,ip1];
+                        }
+                        sblas.symmetricrank2update(ref a, isupper, 1, i, ref t, ref tau, ref t2, -1);
+                        a[i,i+1] = e[i];
+                    }
+                    d[i+1] = a[i+1,i+1];
+                    tau[i] = taui;
+                }
+                d[1] = a[1,1];
+            }
+            else
+            {
+                
+                //
+                // Reduce the lower triangle of A
+                //
+                for(i=1; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Generate elementary reflector H(i) = I - tau * v * v'
+                    // to annihilate A(i+2:n,i)
+                    //
+                    //DLARFG( N-I, A( I+1, I ), A( MIN( I+2, N ), I ), 1, TAUI );
+                    //
+                    nmi = n-i;
+                    ip1 = i+1;
+                    i1_ = (ip1) - (1);
+                    for(i_=1; i_<=nmi;i_++)
+                    {
+                        t[i_] = a[i_+i1_,i];
+                    }
+                    reflections.generatereflection(ref t, nmi, ref taui);
+                    i1_ = (1) - (ip1);
+                    for(i_=ip1; i_<=n;i_++)
+                    {
+                        a[i_,i] = t[i_+i1_];
+                    }
+                    e[i] = a[i+1,i];
+                    if( (double)(taui)!=(double)(0) )
+                    {
+                        
+                        //
+                        // Apply H(i) from both sides to A(i+1:n,i+1:n)
+                        //
+                        a[i+1,i] = 1;
+                        
+                        //
+                        // Compute  x := tau * A * v  storing y in TAU(i:n-1)
+                        //
+                        //DSYMV( UPLO, N-I, TAUI, A( I+1, I+1 ), LDA, A( I+1, I ), 1, ZERO, TAU( I ), 1 );
+                        //
+                        ip1 = i+1;
+                        nmi = n-i;
+                        nm1 = n-1;
+                        i1_ = (ip1) - (1);
+                        for(i_=1; i_<=nmi;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        sblas.symmetricmatrixvectormultiply(ref a, isupper, i+1, n, ref t, taui, ref t2);
+                        i1_ = (1) - (i);
+                        for(i_=i; i_<=nm1;i_++)
+                        {
+                            tau[i_] = t2[i_+i1_];
+                        }
+                        
+                        //
+                        // Compute  w := x - 1/2 * tau * (x'*v) * v
+                        //
+                        nm1 = n-1;
+                        ip1 = i+1;
+                        i1_ = (ip1)-(i);
+                        v = 0.0;
+                        for(i_=i; i_<=nm1;i_++)
+                        {
+                            v += tau[i_]*a[i_+i1_,i];
+                        }
+                        alpha = -(0.5*taui*v);
+                        i1_ = (ip1) - (i);
+                        for(i_=i; i_<=nm1;i_++)
+                        {
+                            tau[i_] = tau[i_] + alpha*a[i_+i1_,i];
+                        }
+                        
+                        //
+                        // Apply the transformation as a rank-2 update:
+                        //     A := A - v * w' - w * v'
+                        //
+                        //DSYR2( UPLO, N-I, -ONE, A( I+1, I ), 1, TAU( I ), 1, A( I+1, I+1 ), LDA );
+                        //
+                        nm1 = n-1;
+                        nmi = n-i;
+                        ip1 = i+1;
+                        i1_ = (ip1) - (1);
+                        for(i_=1; i_<=nmi;i_++)
+                        {
+                            t[i_] = a[i_+i1_,i];
+                        }
+                        i1_ = (i) - (1);
+                        for(i_=1; i_<=nmi;i_++)
+                        {
+                            t2[i_] = tau[i_+i1_];
+                        }
+                        sblas.symmetricrank2update(ref a, isupper, i+1, n, ref t, ref t2, ref t3, -1);
+                        a[i+1,i] = e[i];
+                    }
+                    d[i] = a[i,i];
+                    tau[i] = taui;
+                }
+                d[n] = a[n,n];
+            }
+        }
+
+
+        public static void unpackqfromtridiagonal(ref double[,] a,
+            int n,
+            bool isupper,
+            ref double[] tau,
+            ref double[,] q)
+        {
+            int i = 0;
+            int j = 0;
+            int ip1 = 0;
+            int nmi = 0;
+            double[] v = new double[0];
+            double[] work = new double[0];
+            int i_ = 0;
+            int i1_ = 0;
+
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // init
+            //
+            q = new double[n+1, n+1];
+            v = new double[n+1];
+            work = new double[n+1];
+            for(i=1; i<=n; i++)
+            {
+                for(j=1; j<=n; j++)
+                {
+                    if( i==j )
+                    {
+                        q[i,j] = 1;
+                    }
+                    else
+                    {
+                        q[i,j] = 0;
+                    }
+                }
+            }
+            
+            //
+            // unpack Q
+            //
+            if( isupper )
+            {
+                for(i=1; i<=n-1; i++)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    ip1 = i+1;
+                    for(i_=1; i_<=i;i_++)
+                    {
+                        v[i_] = a[i_,ip1];
+                    }
+                    v[i] = 1;
+                    reflections.applyreflectionfromtheleft(ref q, tau[i], ref v, 1, i, 1, n, ref work);
+                }
+            }
+            else
+            {
+                for(i=n-1; i>=1; i--)
+                {
+                    
+                    //
+                    // Apply H(i)
+                    //
+                    ip1 = i+1;
+                    nmi = n-i;
+                    i1_ = (ip1) - (1);
+                    for(i_=1; i_<=nmi;i_++)
+                    {
+                        v[i_] = a[i_+i1_,i];
+                    }
+                    v[1] = 1;
+                    reflections.applyreflectionfromtheleft(ref q, tau[i], ref v, i+1, n, 1, n, ref work);
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trigintegrals.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trigintegrals.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trigintegrals.cs	(revision 2645)
@@ -0,0 +1,477 @@
+/*************************************************************************
+Cephes Math Library Release 2.8:  June, 2000
+Copyright by Stephen L. Moshier
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from C to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class trigintegrals
+    {
+        /*************************************************************************
+        Sine and cosine integrals
+
+        Evaluates the integrals
+
+                                 x
+                                 -
+                                |  cos t - 1
+          Ci(x) = eul + ln x +  |  --------- dt,
+                                |      t
+                               -
+                                0
+                    x
+                    -
+                   |  sin t
+          Si(x) =  |  ----- dt
+                   |    t
+                  -
+                   0
+
+        where eul = 0.57721566490153286061 is Euler's constant.
+        The integrals are approximated by rational functions.
+        For x > 8 auxiliary functions f(x) and g(x) are employed
+        such that
+
+        Ci(x) = f(x) sin(x) - g(x) cos(x)
+        Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x)
+
+
+        ACCURACY:
+           Test interval = [0,50].
+        Absolute error, except relative when > 1:
+        arithmetic   function   # trials      peak         rms
+           IEEE        Si        30000       4.4e-16     7.3e-17
+           IEEE        Ci        30000       6.9e-16     5.1e-17
+
+        Cephes Math Library Release 2.1:  January, 1989
+        Copyright 1984, 1987, 1989 by Stephen L. Moshier
+        *************************************************************************/
+        public static void sinecosineintegrals(double x,
+            ref double si,
+            ref double ci)
+        {
+            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;
+
+            if( (double)(x)<(double)(0) )
+            {
+                sg = -1;
+                x = -x;
+            }
+            else
+            {
+                sg = 0;
+            }
+            if( (double)(x)==(double)(0) )
+            {
+                si = 0;
+                ci = -AP.Math.MaxRealNumber;
+                return;
+            }
+            if( (double)(x)>(double)(1.0E9) )
+            {
+                si = 1.570796326794896619-Math.Cos(x)/x;
+                ci = Math.Sin(x)/x;
+                return;
+            }
+            if( (double)(x)<=(double)(4) )
+            {
+                z = x*x;
+                sn = -8.39167827910303881427E-11;
+                sn = sn*z+4.62591714427012837309E-8;
+                sn = sn*z-9.75759303843632795789E-6;
+                sn = sn*z+9.76945438170435310816E-4;
+                sn = sn*z-4.13470316229406538752E-2;
+                sn = sn*z+1.00000000000000000302E0;
+                sd = 2.03269266195951942049E-12;
+                sd = sd*z+1.27997891179943299903E-9;
+                sd = sd*z+4.41827842801218905784E-7;
+                sd = sd*z+9.96412122043875552487E-5;
+                sd = sd*z+1.42085239326149893930E-2;
+                sd = sd*z+9.99999999999999996984E-1;
+                s = x*sn/sd;
+                cn = 2.02524002389102268789E-11;
+                cn = cn*z-1.35249504915790756375E-8;
+                cn = cn*z+3.59325051419993077021E-6;
+                cn = cn*z-4.74007206873407909465E-4;
+                cn = cn*z+2.89159652607555242092E-2;
+                cn = cn*z-1.00000000000000000080E0;
+                cd = 4.07746040061880559506E-12;
+                cd = cd*z+3.06780997581887812692E-9;
+                cd = cd*z+1.23210355685883423679E-6;
+                cd = cd*z+3.17442024775032769882E-4;
+                cd = cd*z+5.10028056236446052392E-2;
+                cd = cd*z+4.00000000000000000080E0;
+                c = z*cn/cd;
+                if( sg!=0 )
+                {
+                    s = -s;
+                }
+                si = s;
+                ci = 0.57721566490153286061+Math.Log(x)+c;
+                return;
+            }
+            s = Math.Sin(x);
+            c = Math.Cos(x);
+            z = 1.0/(x*x);
+            if( (double)(x)<(double)(8) )
+            {
+                fn = 4.23612862892216586994E0;
+                fn = fn*z+5.45937717161812843388E0;
+                fn = fn*z+1.62083287701538329132E0;
+                fn = fn*z+1.67006611831323023771E-1;
+                fn = fn*z+6.81020132472518137426E-3;
+                fn = fn*z+1.08936580650328664411E-4;
+                fn = fn*z+5.48900223421373614008E-7;
+                fd = 1.00000000000000000000E0;
+                fd = fd*z+8.16496634205391016773E0;
+                fd = fd*z+7.30828822505564552187E0;
+                fd = fd*z+1.86792257950184183883E0;
+                fd = fd*z+1.78792052963149907262E-1;
+                fd = fd*z+7.01710668322789753610E-3;
+                fd = fd*z+1.10034357153915731354E-4;
+                fd = fd*z+5.48900252756255700982E-7;
+                f = fn/(x*fd);
+                gn = 8.71001698973114191777E-2;
+                gn = gn*z+6.11379109952219284151E-1;
+                gn = gn*z+3.97180296392337498885E-1;
+                gn = gn*z+7.48527737628469092119E-2;
+                gn = gn*z+5.38868681462177273157E-3;
+                gn = gn*z+1.61999794598934024525E-4;
+                gn = gn*z+1.97963874140963632189E-6;
+                gn = gn*z+7.82579040744090311069E-9;
+                gd = 1.00000000000000000000E0;
+                gd = gd*z+1.64402202413355338886E0;
+                gd = gd*z+6.66296701268987968381E-1;
+                gd = gd*z+9.88771761277688796203E-2;
+                gd = gd*z+6.22396345441768420760E-3;
+                gd = gd*z+1.73221081474177119497E-4;
+                gd = gd*z+2.02659182086343991969E-6;
+                gd = gd*z+7.82579218933534490868E-9;
+                g = z*gn/gd;
+            }
+            else
+            {
+                fn = 4.55880873470465315206E-1;
+                fn = fn*z+7.13715274100146711374E-1;
+                fn = fn*z+1.60300158222319456320E-1;
+                fn = fn*z+1.16064229408124407915E-2;
+                fn = fn*z+3.49556442447859055605E-4;
+                fn = fn*z+4.86215430826454749482E-6;
+                fn = fn*z+3.20092790091004902806E-8;
+                fn = fn*z+9.41779576128512936592E-11;
+                fn = fn*z+9.70507110881952024631E-14;
+                fd = 1.00000000000000000000E0;
+                fd = fd*z+9.17463611873684053703E-1;
+                fd = fd*z+1.78685545332074536321E-1;
+                fd = fd*z+1.22253594771971293032E-2;
+                fd = fd*z+3.58696481881851580297E-4;
+                fd = fd*z+4.92435064317881464393E-6;
+                fd = fd*z+3.21956939101046018377E-8;
+                fd = fd*z+9.43720590350276732376E-11;
+                fd = fd*z+9.70507110881952025725E-14;
+                f = fn/(x*fd);
+                gn = 6.97359953443276214934E-1;
+                gn = gn*z+3.30410979305632063225E-1;
+                gn = gn*z+3.84878767649974295920E-2;
+                gn = gn*z+1.71718239052347903558E-3;
+                gn = gn*z+3.48941165502279436777E-5;
+                gn = gn*z+3.47131167084116673800E-7;
+                gn = gn*z+1.70404452782044526189E-9;
+                gn = gn*z+3.85945925430276600453E-12;
+                gn = gn*z+3.14040098946363334640E-15;
+                gd = 1.00000000000000000000E0;
+                gd = gd*z+1.68548898811011640017E0;
+                gd = gd*z+4.87852258695304967486E-1;
+                gd = gd*z+4.67913194259625806320E-2;
+                gd = gd*z+1.90284426674399523638E-3;
+                gd = gd*z+3.68475504442561108162E-5;
+                gd = gd*z+3.57043223443740838771E-7;
+                gd = gd*z+1.72693748966316146736E-9;
+                gd = gd*z+3.87830166023954706752E-12;
+                gd = gd*z+3.14040098946363335242E-15;
+                g = z*gn/gd;
+            }
+            si = 1.570796326794896619-f*c-g*s;
+            if( sg!=0 )
+            {
+                si = -si;
+            }
+            ci = f*s-g*c;
+        }
+
+
+        /*************************************************************************
+        Hyperbolic sine and cosine integrals
+
+        Approximates the integrals
+
+                                   x
+                                   -
+                                  | |   cosh t - 1
+          Chi(x) = eul + ln x +   |    -----------  dt,
+                                | |          t
+                                 -
+                                 0
+
+                      x
+                      -
+                     | |  sinh t
+          Shi(x) =   |    ------  dt
+                   | |       t
+                    -
+                    0
+
+        where eul = 0.57721566490153286061 is Euler's constant.
+        The integrals are evaluated by power series for x < 8
+        and by Chebyshev expansions for x between 8 and 88.
+        For large x, both functions approach exp(x)/2x.
+        Arguments greater than 88 in magnitude return MAXNUM.
+
+
+        ACCURACY:
+
+        Test interval 0 to 88.
+                             Relative error:
+        arithmetic   function  # trials      peak         rms
+           IEEE         Shi      30000       6.9e-16     1.6e-16
+               Absolute error, except relative when |Chi| > 1:
+           IEEE         Chi      30000       8.4e-16     1.4e-16
+
+        Cephes Math Library Release 2.8:  June, 2000
+        Copyright 1984, 1987, 2000 by Stephen L. Moshier
+        *************************************************************************/
+        public static void hyperbolicsinecosineintegrals(double x,
+            ref double shi,
+            ref double chi)
+        {
+            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;
+
+            if( (double)(x)<(double)(0) )
+            {
+                sg = -1;
+                x = -x;
+            }
+            else
+            {
+                sg = 0;
+            }
+            if( (double)(x)==(double)(0) )
+            {
+                shi = 0;
+                chi = -AP.Math.MaxRealNumber;
+                return;
+            }
+            if( (double)(x)<(double)(8.0) )
+            {
+                z = x*x;
+                a = 1.0;
+                s = 1.0;
+                c = 0.0;
+                k = 2.0;
+                do
+                {
+                    a = a*z/k;
+                    c = c+a/k;
+                    k = k+1.0;
+                    a = a/k;
+                    s = s+a/k;
+                    k = k+1.0;
+                }
+                while( (double)(Math.Abs(a/s))>=(double)(AP.Math.MachineEpsilon) );
+                s = s*x;
+            }
+            else
+            {
+                if( (double)(x)<(double)(18.0) )
+                {
+                    a = (576.0/x-52.0)/10.0;
+                    k = Math.Exp(x)/x;
+                    b0 = 1.83889230173399459482E-17;
+                    b1 = 0.0;
+                    chebiterationshichi(a, -9.55485532279655569575E-17, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 2.04326105980879882648E-16, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.09896949074905343022E-15, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.31313534344092599234E-14, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 5.93976226264314278932E-14, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -3.47197010497749154755E-14, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.40059764613117131000E-12, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 9.49044626224223543299E-12, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.61596181145435454033E-11, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.77899784436430310321E-10, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.35455469767246947469E-9, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.03257121792819495123E-9, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -3.56699611114982536845E-8, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.44818877384267342057E-7, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 7.82018215184051295296E-7, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -5.39919118403805073710E-6, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -3.12458202168959833422E-5, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 8.90136741950727517826E-5, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 2.02558474743846862168E-3, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 2.96064440855633256972E-2, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.11847751047257036625E0, ref b0, ref b1, ref b2);
+                    s = k*0.5*(b0-b2);
+                    b0 = -8.12435385225864036372E-18;
+                    b1 = 0.0;
+                    chebiterationshichi(a, 2.17586413290339214377E-17, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 5.22624394924072204667E-17, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -9.48812110591690559363E-16, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 5.35546311647465209166E-15, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.21009970113732918701E-14, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -6.00865178553447437951E-14, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 7.16339649156028587775E-13, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -2.93496072607599856104E-12, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.40359438136491256904E-12, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 8.76302288609054966081E-11, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -4.40092476213282340617E-10, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -1.87992075640569295479E-10, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.31458150989474594064E-8, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -4.75513930924765465590E-8, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -2.21775018801848880741E-7, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.94635531373272490962E-6, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 4.33505889257316408893E-6, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -6.13387001076494349496E-5, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, -3.13085477492997465138E-4, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 4.97164789823116062801E-4, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 2.64347496031374526641E-2, ref b0, ref b1, ref b2);
+                    chebiterationshichi(a, 1.11446150876699213025E0, ref b0, ref b1, ref b2);
+                    c = k*0.5*(b0-b2);
+                }
+                else
+                {
+                    if( (double)(x)<=(double)(88.0) )
+                    {
+                        a = (6336.0/x-212.0)/70.0;
+                        k = Math.Exp(x)/x;
+                        b0 = -1.05311574154850938805E-17;
+                        b1 = 0.0;
+                        chebiterationshichi(a, 2.62446095596355225821E-17, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 8.82090135625368160657E-17, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -3.38459811878103047136E-16, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -8.30608026366935789136E-16, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 3.93397875437050071776E-15, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.01765565969729044505E-14, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -4.21128170307640802703E-14, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -1.60818204519802480035E-13, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 3.34714954175994481761E-13, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 2.72600352129153073807E-12, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.66894954752839083608E-12, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -3.49278141024730899554E-11, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -1.58580661666482709598E-10, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -1.79289437183355633342E-10, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.76281629144264523277E-9, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.69050228879421288846E-8, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.25391771228487041649E-7, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.16229947068677338732E-6, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.61038260117376323993E-5, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 3.49810375601053973070E-4, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.28478065259647610779E-2, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.03665722588798326712E0, ref b0, ref b1, ref b2);
+                        s = k*0.5*(b0-b2);
+                        b0 = 8.06913408255155572081E-18;
+                        b1 = 0.0;
+                        chebiterationshichi(a, -2.08074168180148170312E-17, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -5.98111329658272336816E-17, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 2.68533951085945765591E-16, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 4.52313941698904694774E-16, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -3.10734917335299464535E-15, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -4.42823207332531972288E-15, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 3.49639695410806959872E-14, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 6.63406731718911586609E-14, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -3.71902448093119218395E-13, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -1.27135418132338309016E-12, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 2.74851141935315395333E-12, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 2.33781843985453438400E-11, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 2.71436006377612442764E-11, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -2.56600180000355990529E-10, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -1.61021375163803438552E-9, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -4.72543064876271773512E-9, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, -3.00095178028681682282E-9, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 7.79387474390914922337E-8, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.06942765566401507066E-6, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.59503164802313196374E-5, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 3.49592575153777996871E-4, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.28475387530065247392E-2, ref b0, ref b1, ref b2);
+                        chebiterationshichi(a, 1.03665693917934275131E0, ref b0, ref b1, ref b2);
+                        c = k*0.5*(b0-b2);
+                    }
+                    else
+                    {
+                        if( sg!=0 )
+                        {
+                            shi = -AP.Math.MaxRealNumber;
+                        }
+                        else
+                        {
+                            shi = AP.Math.MaxRealNumber;
+                        }
+                        chi = AP.Math.MaxRealNumber;
+                        return;
+                    }
+                }
+            }
+            if( sg!=0 )
+            {
+                s = -s;
+            }
+            shi = s;
+            chi = 0.57721566490153286061+Math.Log(x)+c;
+        }
+
+
+        private static void chebiterationshichi(double x,
+            double c,
+            ref double b0,
+            ref double b1,
+            ref double b2)
+        {
+            b2 = b1;
+            b1 = b0;
+            b0 = x*b1-b2+c;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trinverse.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trinverse.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trinverse.cs	(revision 2645)
@@ -0,0 +1,373 @@
+/*************************************************************************
+Copyright (c) 1992-2007 The University of Tennessee.  All rights reserved.
+
+Contributors:
+    * Sergey Bochkanov (ALGLIB project). Translation from FORTRAN to
+      pseudocode.
+
+See subroutines comments for additional copyrights.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class trinverse
+    {
+        /*************************************************************************
+        Triangular matrix inversion
+
+        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 whose indexes range within [0..N-1, 0..N-1].
+            N       -   size of matrix A.
+            IsUpper -   True, if the matrix is upper triangular.
+            IsunitTriangular
+                    -   True, if the matrix has a unit diagonal.
+
+        Output parameters:
+            A       -   inverse matrix (if the problem is not degenerate).
+
+        Result:
+            True, if the matrix is not singular.
+            False, if the matrix is singular.
+
+          -- 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
+        *************************************************************************/
+        public static bool rmatrixtrinverse(ref double[,] a,
+            int n,
+            bool isupper,
+            bool isunittriangular)
+        {
+            bool result = new bool();
+            bool nounit = new bool();
+            int i = 0;
+            int j = 0;
+            double v = 0;
+            double ajj = 0;
+            double[] t = new double[0];
+            int i_ = 0;
+
+            result = true;
+            t = new double[n-1+1];
+            
+            //
+            // Test the input parameters.
+            //
+            nounit = !isunittriangular;
+            if( isupper )
+            {
+                
+                //
+                // Compute inverse of upper triangular matrix.
+                //
+                for(j=0; j<=n-1; j++)
+                {
+                    if( nounit )
+                    {
+                        if( (double)(a[j,j])==(double)(0) )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    
+                    //
+                    // Compute elements 1:j-1 of j-th column.
+                    //
+                    if( j>0 )
+                    {
+                        for(i_=0; i_<=j-1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=0; i<=j-1; i++)
+                        {
+                            if( i<j-1 )
+                            {
+                                v = 0.0;
+                                for(i_=i+1; i_<=j-1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=0; i_<=j-1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inverse of lower triangular matrix.
+                //
+                for(j=n-1; j>=0; j--)
+                {
+                    if( nounit )
+                    {
+                        if( (double)(a[j,j])==(double)(0) )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    if( j<n-1 )
+                    {
+                        
+                        //
+                        // Compute elements j+1:n of j-th column.
+                        //
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=j+1; i<=n-1; i++)
+                        {
+                            if( i>j+1 )
+                            {
+                                v = 0.0;
+                                for(i_=j+1; i_<=i-1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=j+1; i_<=n-1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+
+
+        public static bool invtriangular(ref double[,] a,
+            int n,
+            bool isupper,
+            bool isunittriangular)
+        {
+            bool result = new bool();
+            bool nounit = new bool();
+            int i = 0;
+            int j = 0;
+            int nmj = 0;
+            int jm1 = 0;
+            int jp1 = 0;
+            double v = 0;
+            double ajj = 0;
+            double[] t = new double[0];
+            int i_ = 0;
+
+            result = true;
+            t = new double[n+1];
+            
+            //
+            // Test the input parameters.
+            //
+            nounit = !isunittriangular;
+            if( isupper )
+            {
+                
+                //
+                // Compute inverse of upper triangular matrix.
+                //
+                for(j=1; j<=n; j++)
+                {
+                    if( nounit )
+                    {
+                        if( (double)(a[j,j])==(double)(0) )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    
+                    //
+                    // Compute elements 1:j-1 of j-th column.
+                    //
+                    if( j>1 )
+                    {
+                        jm1 = j-1;
+                        for(i_=1; i_<=jm1;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=1; i<=j-1; i++)
+                        {
+                            if( i<j-1 )
+                            {
+                                v = 0.0;
+                                for(i_=i+1; i_<=jm1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=1; i_<=jm1;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            else
+            {
+                
+                //
+                // Compute inverse of lower triangular matrix.
+                //
+                for(j=n; j>=1; j--)
+                {
+                    if( nounit )
+                    {
+                        if( (double)(a[j,j])==(double)(0) )
+                        {
+                            result = false;
+                            return result;
+                        }
+                        a[j,j] = 1/a[j,j];
+                        ajj = -a[j,j];
+                    }
+                    else
+                    {
+                        ajj = -1;
+                    }
+                    if( j<n )
+                    {
+                        
+                        //
+                        // Compute elements j+1:n of j-th column.
+                        //
+                        nmj = n-j;
+                        jp1 = j+1;
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            t[i_] = a[i_,j];
+                        }
+                        for(i=j+1; i<=n; i++)
+                        {
+                            if( i>j+1 )
+                            {
+                                v = 0.0;
+                                for(i_=jp1; i_<=i-1;i_++)
+                                {
+                                    v += a[i,i_]*t[i_];
+                                }
+                            }
+                            else
+                            {
+                                v = 0;
+                            }
+                            if( nounit )
+                            {
+                                a[i,j] = v+a[i,i]*t[i];
+                            }
+                            else
+                            {
+                                a[i,j] = v+t[i];
+                            }
+                        }
+                        for(i_=jp1; i_<=n;i_++)
+                        {
+                            a[i_,j] = ajj*a[i_,j];
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trlinsolve.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trlinsolve.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/trlinsolve.cs	(revision 2645)
@@ -0,0 +1,1022 @@
+/*************************************************************************
+This file is a part of ALGLIB project.
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class trlinsolve
+    {
+        /*************************************************************************
+        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
+        *************************************************************************/
+        public static void rmatrixtrsafesolve(ref double[,] a,
+            int n,
+            ref double[] x,
+            ref double s,
+            bool isupper,
+            bool istrans,
+            bool isunit)
+        {
+            bool normin = new bool();
+            double[] cnorm = new double[0];
+            double[,] a1 = new double[0,0];
+            double[] x1 = new double[0];
+            int i = 0;
+            int i_ = 0;
+            int i1_ = 0;
+
+            
+            //
+            // From 0-based to 1-based
+            //
+            normin = false;
+            a1 = new double[n+1, n+1];
+            x1 = new double[n+1];
+            for(i=1; i<=n; i++)
+            {
+                i1_ = (0) - (1);
+                for(i_=1; i_<=n;i_++)
+                {
+                    a1[i,i_] = a[i-1,i_+i1_];
+                }
+            }
+            i1_ = (0) - (1);
+            for(i_=1; i_<=n;i_++)
+            {
+                x1[i_] = x[i_+i1_];
+            }
+            
+            //
+            // Solve 1-based
+            //
+            safesolvetriangular(ref a1, n, ref x1, ref s, isupper, istrans, isunit, normin, ref cnorm);
+            
+            //
+            // From 1-based to 0-based
+            //
+            i1_ = (1) - (0);
+            for(i_=0; i_<=n-1;i_++)
+            {
+                x[i_] = x1[i_+i1_];
+            }
+        }
+
+
+        /*************************************************************************
+        Obsolete 1-based subroutine.
+        See RMatrixTRSafeSolve for 0-based replacement.
+        *************************************************************************/
+        public static void safesolvetriangular(ref double[,] a,
+            int n,
+            ref double[] x,
+            ref double s,
+            bool isupper,
+            bool istrans,
+            bool isunit,
+            bool normin,
+            ref double[] cnorm)
+        {
+            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 = new bool();
+            bool upper = new bool();
+            bool nounit = new bool();
+            int i_ = 0;
+
+            upper = isupper;
+            notran = !istrans;
+            nounit = !isunit;
+            
+            //
+            // Quick return if possible
+            //
+            if( n==0 )
+            {
+                return;
+            }
+            
+            //
+            // Determine machine dependent parameters to control overflow.
+            //
+            smlnum = AP.Math.MinRealNumber/(AP.Math.MachineEpsilon*2);
+            bignum = 1/smlnum;
+            s = 1;
+            if( !normin )
+            {
+                cnorm = new double[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+Math.Abs(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+Math.Abs(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++)
+            {
+                if( (double)(cnorm[k])>(double)(cnorm[imax]) )
+                {
+                    imax = k;
+                }
+            }
+            tmax = cnorm[imax];
+            if( (double)(tmax)<=(double)(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++)
+            {
+                if( (double)(Math.Abs(x[k]))>(double)(Math.Abs(x[j])) )
+                {
+                    j = k;
+                }
+            }
+            xmax = Math.Abs(x[j]);
+            xbnd = xmax;
+            if( notran )
+            {
+                
+                //
+                // Compute the growth in A * x = b.
+                //
+                if( upper )
+                {
+                    jfirst = n;
+                    jlast = 1;
+                    jinc = -1;
+                }
+                else
+                {
+                    jfirst = 1;
+                    jlast = n;
+                    jinc = 1;
+                }
+                if( (double)(tscal)!=(double)(1) )
+                {
+                    grow = 0;
+                }
+                else
+                {
+                    if( nounit )
+                    {
+                        
+                        //
+                        // A is non-unit triangular.
+                        //
+                        // Compute GROW = 1/G(j) and XBND = 1/M(j).
+                        // Initially, G(0) = max{x(i), i=1,...,n}.
+                        //
+                        grow = 1/Math.Max(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( (double)(grow)<=(double)(smlnum) )
+                            {
+                                break;
+                            }
+                            
+                            //
+                            // M(j) = G(j-1) / abs(A(j,j))
+                            //
+                            tjj = Math.Abs(a[j,j]);
+                            xbnd = Math.Min(xbnd, Math.Min(1, tjj)*grow);
+                            if( (double)(tjj+cnorm[j])>=(double)(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;
+                            }
+                            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 = Math.Min(1, 1/Math.Max(xbnd, smlnum));
+                        j = jfirst;
+                        while( jinc>0 & j<=jlast | jinc<0 & j>=jlast )
+                        {
+                            
+                            //
+                            // Exit the loop if the growth factor is too small.
+                            //
+                            if( (double)(grow)<=(double)(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;
+                }
+                if( (double)(tscal)!=(double)(1) )
+                {
+                    grow = 0;
+                }
+                else
+                {
+                    if( nounit )
+                    {
+                        
+                        //
+                        // A is non-unit triangular.
+                        //
+                        // Compute GROW = 1/G(j) and XBND = 1/M(j).
+                        // Initially, M(0) = max{x(i), i=1,...,n}.
+                        //
+                        grow = 1/Math.Max(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( (double)(grow)<=(double)(smlnum) )
+                            {
+                                break;
+                            }
+                            
+                            //
+                            // G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) )
+                            //
+                            xj = 1+cnorm[j];
+                            grow = Math.Min(grow, xbnd/xj);
+                            
+                            //
+                            // M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j))
+                            //
+                            tjj = Math.Abs(a[j,j]);
+                            if( (double)(xj)>(double)(tjj) )
+                            {
+                                xbnd = xbnd*(tjj/xj);
+                            }
+                            if( j==jlast )
+                            {
+                                grow = Math.Min(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 = Math.Min(1, 1/Math.Max(xbnd, smlnum));
+                        j = jfirst;
+                        while( jinc>0 & j<=jlast | jinc<0 & j>=jlast )
+                        {
+                            
+                            //
+                            // Exit the loop if the growth factor is too small.
+                            //
+                            if( (double)(grow)<=(double)(smlnum) )
+                            {
+                                break;
+                            }
+                            
+                            //
+                            // G(j) = ( 1 + CNORM(j) )*G(j-1)
+                            //
+                            xj = 1+cnorm[j];
+                            grow = grow/xj;
+                            j = j+jinc;
+                        }
+                    }
+                }
+            }
+            if( (double)(grow*tscal)>(double)(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 )
+                {
+                    if( nounit )
+                    {
+                        vd = a[n,n];
+                    }
+                    else
+                    {
+                        vd = 1;
+                    }
+                    x[n] = x[n]/vd;
+                    for(i=n-1; i>=1; i--)
+                    {
+                        ip1 = i+1;
+                        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_];
+                            }
+                        }
+                        if( nounit )
+                        {
+                            vd = a[i,i];
+                        }
+                        else
+                        {
+                            vd = 1;
+                        }
+                        x[i] = (x[i]-v)/vd;
+                    }
+                }
+                else
+                {
+                    if( nounit )
+                    {
+                        vd = a[1,1];
+                    }
+                    else
+                    {
+                        vd = 1;
+                    }
+                    x[1] = x[1]/vd;
+                    for(i=2; i<=n; i++)
+                    {
+                        im1 = i-1;
+                        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_];
+                            }
+                        }
+                        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( (double)(xmax)>(double)(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;
+                }
+                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 = Math.Abs(x[j]);
+                        flg = 0;
+                        if( nounit )
+                        {
+                            tjjs = a[j,j]*tscal;
+                        }
+                        else
+                        {
+                            tjjs = tscal;
+                            if( (double)(tscal)==(double)(1) )
+                            {
+                                flg = 100;
+                            }
+                        }
+                        if( flg!=100 )
+                        {
+                            tjj = Math.Abs(tjjs);
+                            if( (double)(tjj)>(double)(smlnum) )
+                            {
+                                
+                                //
+                                // abs(A(j,j)) > SMLNUM:
+                                //
+                                if( (double)(tjj)<(double)(1) )
+                                {
+                                    if( (double)(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 = Math.Abs(x[j]);
+                            }
+                            else
+                            {
+                                if( (double)(tjj)>(double)(0) )
+                                {
+                                    
+                                    //
+                                    // 0 < abs(A(j,j)) <= SMLNUM:
+                                    //
+                                    if( (double)(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;
+                                        if( (double)(cnorm[j])>(double)(1) )
+                                        {
+                                            
+                                            //
+                                            // 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 = Math.Abs(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;
+                                    }
+                                    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( (double)(xj)>(double)(1) )
+                        {
+                            rec = 1/xj;
+                            if( (double)(cnorm[j])>(double)((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
+                        {
+                            if( (double)(xj*cnorm[j])>(double)(bignum-xmax) )
+                            {
+                                
+                                //
+                                // Scale x by 1/2.
+                                //
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    x[i_] = 0.5*x[i_];
+                                }
+                                s = s*0.5;
+                            }
+                        }
+                        if( upper )
+                        {
+                            if( j>1 )
+                            {
+                                
+                                //
+                                // Compute the update
+                                // x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j)
+                                //
+                                v = x[j]*tscal;
+                                jm1 = j-1;
+                                for(i_=1; i_<=jm1;i_++)
+                                {
+                                    x[i_] = x[i_] - v*a[i_,j];
+                                }
+                                i = 1;
+                                for(k=2; k<=j-1; k++)
+                                {
+                                    if( (double)(Math.Abs(x[k]))>(double)(Math.Abs(x[i])) )
+                                    {
+                                        i = k;
+                                    }
+                                }
+                                xmax = Math.Abs(x[i]);
+                            }
+                        }
+                        else
+                        {
+                            if( j<n )
+                            {
+                                
+                                //
+                                // Compute the update
+                                // x(j+1:n) := x(j+1:n) - x(j) * A(j+1:n,j)
+                                //
+                                jp1 = j+1;
+                                v = x[j]*tscal;
+                                for(i_=jp1; i_<=n;i_++)
+                                {
+                                    x[i_] = x[i_] - v*a[i_,j];
+                                }
+                                i = j+1;
+                                for(k=j+2; k<=n; k++)
+                                {
+                                    if( (double)(Math.Abs(x[k]))>(double)(Math.Abs(x[i])) )
+                                    {
+                                        i = k;
+                                    }
+                                }
+                                xmax = Math.Abs(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 = Math.Abs(x[j]);
+                        uscal = tscal;
+                        rec = 1/Math.Max(xmax, 1);
+                        if( (double)(cnorm[j])>(double)((bignum-xj)*rec) )
+                        {
+                            
+                            //
+                            // If x(j) could overflow, scale x by 1/(2*XMAX).
+                            //
+                            rec = rec*0.5;
+                            if( nounit )
+                            {
+                                tjjs = a[j,j]*tscal;
+                            }
+                            else
+                            {
+                                tjjs = tscal;
+                            }
+                            tjj = Math.Abs(tjjs);
+                            if( (double)(tjj)>(double)(1) )
+                            {
+                                
+                                //
+                                // Divide by A(j,j) when scaling x if A(j,j) > 1.
+                                //
+                                rec = Math.Min(1, rec*tjj);
+                                uscal = uscal/tjjs;
+                            }
+                            if( (double)(rec)<(double)(1) )
+                            {
+                                for(i_=1; i_<=n;i_++)
+                                {
+                                    x[i_] = rec*x[i_];
+                                }
+                                s = s*rec;
+                                xmax = xmax*rec;
+                            }
+                        }
+                        sumj = 0;
+                        if( (double)(uscal)==(double)(1) )
+                        {
+                            
+                            //
+                            // If the scaling needed for A in the dot product is 1,
+                            // call DDOT to perform the dot product.
+                            //
+                            if( upper )
+                            {
+                                if( j>1 )
+                                {
+                                    jm1 = j-1;
+                                    sumj = 0.0;
+                                    for(i_=1; i_<=jm1;i_++)
+                                    {
+                                        sumj += a[i_,j]*x[i_];
+                                    }
+                                }
+                                else
+                                {
+                                    sumj = 0;
+                                }
+                            }
+                            else
+                            {
+                                if( j<n )
+                                {
+                                    jp1 = j+1;
+                                    sumj = 0.0;
+                                    for(i_=jp1; i_<=n;i_++)
+                                    {
+                                        sumj += a[i_,j]*x[i_];
+                                    }
+                                }
+                            }
+                        }
+                        else
+                        {
+                            
+                            //
+                            // Otherwise, use in-line code for the dot product.
+                            //
+                            if( upper )
+                            {
+                                for(i=1; i<=j-1; i++)
+                                {
+                                    v = a[i,j]*uscal;
+                                    sumj = sumj+v*x[i];
+                                }
+                            }
+                            else
+                            {
+                                if( j<n )
+                                {
+                                    for(i=j+1; i<=n; i++)
+                                    {
+                                        v = a[i,j]*uscal;
+                                        sumj = sumj+v*x[i];
+                                    }
+                                }
+                            }
+                        }
+                        if( (double)(uscal)==(double)(tscal) )
+                        {
+                            
+                            //
+                            // Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j)
+                            // was not used to scale the dotproduct.
+                            //
+                            x[j] = x[j]-sumj;
+                            xj = Math.Abs(x[j]);
+                            flg = 0;
+                            if( nounit )
+                            {
+                                tjjs = a[j,j]*tscal;
+                            }
+                            else
+                            {
+                                tjjs = tscal;
+                                if( (double)(tscal)==(double)(1) )
+                                {
+                                    flg = 150;
+                                }
+                            }
+                            
+                            //
+                            // Compute x(j) = x(j) / A(j,j), scaling if necessary.
+                            //
+                            if( flg!=150 )
+                            {
+                                tjj = Math.Abs(tjjs);
+                                if( (double)(tjj)>(double)(smlnum) )
+                                {
+                                    
+                                    //
+                                    // abs(A(j,j)) > SMLNUM:
+                                    //
+                                    if( (double)(tjj)<(double)(1) )
+                                    {
+                                        if( (double)(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
+                                {
+                                    if( (double)(tjj)>(double)(0) )
+                                    {
+                                        
+                                        //
+                                        // 0 < abs(A(j,j)) <= SMLNUM:
+                                        //
+                                        if( (double)(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 = Math.Max(xmax, Math.Abs(x[j]));
+                        j = j+jinc;
+                    }
+                }
+                s = s/tscal;
+            }
+            
+            //
+            // Scale the column norms by 1/TSCAL for return.
+            //
+            if( (double)(tscal)!=(double)(1) )
+            {
+                v = 1/tscal;
+                for(i_=1; i_<=n;i_++)
+                {
+                    cnorm[i_] = v*cnorm[i_];
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tsort.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tsort.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/tsort.cs	(revision 2645)
@@ -0,0 +1,400 @@
+/*************************************************************************
+Copyright 2008 by Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class tsort
+    {
+        public static void tagsort(ref double[] a,
+            int n,
+            ref int[] p1,
+            ref int[] p2)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            int tmpi = 0;
+            int[] pv = new int[0];
+            int[] vp = new int[0];
+            int lv = 0;
+            int lp = 0;
+            int rv = 0;
+            int rp = 0;
+
+            
+            //
+            // Special cases
+            //
+            if( n<=0 )
+            {
+                return;
+            }
+            if( n==1 )
+            {
+                p1 = new int[0+1];
+                p2 = new int[0+1];
+                p1[0] = 0;
+                p2[0] = 0;
+                return;
+            }
+            
+            //
+            // General case, N>1: prepare permutations table P1
+            //
+            p1 = new int[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                p1[i] = i;
+            }
+            
+            //
+            // General case, N>1: sort, update P1
+            //
+            tagsortfasti(ref a, ref p1, n);
+            
+            //
+            // General case, N>1: fill permutations table P2
+            //
+            // To fill P2 we maintain two arrays:
+            // * PV, Position(Value). PV[i] contains position of I-th key at the moment
+            // * VP, 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.
+            //
+            pv = new int[n-1+1];
+            vp = new int[n-1+1];
+            p2 = new int[n-1+1];
+            for(i=0; i<=n-1; i++)
+            {
+                pv[i] = i;
+                vp[i] = i;
+            }
+            for(i=0; i<=n-1; i++)
+            {
+                
+                //
+                // calculate LP, LV, RP, RV
+                //
+                lp = i;
+                lv = vp[lp];
+                rv = p1[i];
+                rp = pv[rv];
+                
+                //
+                // Fill P2
+                //
+                p2[i] = rp;
+                
+                //
+                // update PV and VP
+                //
+                vp[lp] = rv;
+                vp[rp] = lv;
+                pv[lv] = rp;
+                pv[rv] = lp;
+            }
+        }
+
+
+        public static void tagsortfasti(ref double[] a,
+            ref int[] b,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            int tmpi = 0;
+
+            
+            //
+            // Special cases
+            //
+            if( n<=1 )
+            {
+                return;
+            }
+            
+            //
+            // General case, N>1: sort, update B
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(a[k-1])>=(double)(a[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = a[k-1];
+                        a[k-1] = a[t-1];
+                        a[t-1] = tmp;
+                        tmpi = b[k-1];
+                        b[k-1] = b[t-1];
+                        b[t-1] = tmpi;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = a[i];
+                a[i] = a[0];
+                a[0] = tmp;
+                tmpi = b[i];
+                b[i] = b[0];
+                b[0] = tmpi;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(a[k])>(double)(a[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(a[t-1])>=(double)(a[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = a[k-1];
+                            a[k-1] = a[t-1];
+                            a[t-1] = tmp;
+                            tmpi = b[k-1];
+                            b[k-1] = b[t-1];
+                            b[t-1] = tmpi;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+
+
+        public static void tagsortfastr(ref double[] a,
+            ref double[] b,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            double tmpr = 0;
+
+            
+            //
+            // Special cases
+            //
+            if( n<=1 )
+            {
+                return;
+            }
+            
+            //
+            // General case, N>1: sort, update B
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(a[k-1])>=(double)(a[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = a[k-1];
+                        a[k-1] = a[t-1];
+                        a[t-1] = tmp;
+                        tmpr = b[k-1];
+                        b[k-1] = b[t-1];
+                        b[t-1] = tmpr;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = a[i];
+                a[i] = a[0];
+                a[0] = tmp;
+                tmpr = b[i];
+                b[i] = b[0];
+                b[0] = tmpr;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(a[k])>(double)(a[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(a[t-1])>=(double)(a[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = a[k-1];
+                            a[k-1] = a[t-1];
+                            a[t-1] = tmp;
+                            tmpr = b[k-1];
+                            b[k-1] = b[t-1];
+                            b[t-1] = tmpr;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+
+
+        public static void tagsortfast(ref double[] a,
+            int n)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            double tmpr = 0;
+
+            
+            //
+            // Special cases
+            //
+            if( n<=1 )
+            {
+                return;
+            }
+            
+            //
+            // General case, N>1: sort, update B
+            //
+            i = 2;
+            do
+            {
+                t = i;
+                while( t!=1 )
+                {
+                    k = t/2;
+                    if( (double)(a[k-1])>=(double)(a[t-1]) )
+                    {
+                        t = 1;
+                    }
+                    else
+                    {
+                        tmp = a[k-1];
+                        a[k-1] = a[t-1];
+                        a[t-1] = tmp;
+                        t = k;
+                    }
+                }
+                i = i+1;
+            }
+            while( i<=n );
+            i = n-1;
+            do
+            {
+                tmp = a[i];
+                a[i] = a[0];
+                a[0] = tmp;
+                t = 1;
+                while( t!=0 )
+                {
+                    k = 2*t;
+                    if( k>i )
+                    {
+                        t = 0;
+                    }
+                    else
+                    {
+                        if( k<i )
+                        {
+                            if( (double)(a[k])>(double)(a[k-1]) )
+                            {
+                                k = k+1;
+                            }
+                        }
+                        if( (double)(a[t-1])>=(double)(a[k-1]) )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            tmp = a[k-1];
+                            a[k-1] = a[t-1];
+                            a[t-1] = tmp;
+                            t = k;
+                        }
+                    }
+                }
+                i = i-1;
+            }
+            while( i>=1 );
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/variancetests.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/variancetests.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/variancetests.cs	(revision 2645)
@@ -0,0 +1,235 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class variancetests
+    {
+        /*************************************************************************
+        Two-sample F-test
+
+        This test checks three hypotheses about dispersions of the given  samples.
+        The following tests are performed:
+            * two-tailed test (null hypothesis - the dispersions are equal)
+            * left-tailed test (null hypothesis  -  the  dispersion  of  the first
+              sample is greater than or equal to  the  dispersion  of  the  second
+              sample).
+            * right-tailed test (null hypothesis - the  dispersion  of  the  first
+              sample is less than or equal to the dispersion of the second sample)
+
+        The test is based on the following assumptions:
+            * the given samples have normal distributions
+            * the samples are independent.
+
+        Input parameters:
+            X   -   sample 1. Array whose index goes from 0 to N-1.
+            N   -   sample size.
+            Y   -   sample 2. Array whose index goes from 0 to M-1.
+            M   -   sample size.
+
+        Output parameters:
+            BothTails   -   p-value for two-tailed test.
+                            If BothTails is less than the given significance level
+                            the null hypothesis is rejected.
+            LeftTail    -   p-value for left-tailed test.
+                            If LeftTail is less than the given significance level,
+                            the null hypothesis is rejected.
+            RightTail   -   p-value for right-tailed test.
+                            If RightTail is less than the given significance level
+                            the null hypothesis is rejected.
+
+          -- ALGLIB --
+             Copyright 19.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void ftest(ref double[] x,
+            int n,
+            ref double[] y,
+            int m,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            double xmean = 0;
+            double ymean = 0;
+            double xvar = 0;
+            double yvar = 0;
+            double p = 0;
+            int df1 = 0;
+            int df2 = 0;
+            double stat = 0;
+
+            if( n<=2 | m<=2 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            xmean = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xmean = xmean+x[i];
+            }
+            xmean = xmean/n;
+            ymean = 0;
+            for(i=0; i<=m-1; i++)
+            {
+                ymean = ymean+y[i];
+            }
+            ymean = ymean/m;
+            
+            //
+            // Variance (using corrected two-pass algorithm)
+            //
+            xvar = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xvar = xvar+AP.Math.Sqr(x[i]-xmean);
+            }
+            xvar = xvar/(n-1);
+            yvar = 0;
+            for(i=0; i<=m-1; i++)
+            {
+                yvar = yvar+AP.Math.Sqr(y[i]-ymean);
+            }
+            yvar = yvar/(m-1);
+            if( (double)(xvar)==(double)(0) | (double)(yvar)==(double)(0) )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Statistic
+            //
+            df1 = n-1;
+            df2 = m-1;
+            stat = Math.Min(xvar/yvar, yvar/xvar);
+            bothtails = 1-(fdistr.fdistribution(df1, df2, 1/stat)-fdistr.fdistribution(df1, df2, stat));
+            lefttail = fdistr.fdistribution(df1, df2, xvar/yvar);
+            righttail = 1-lefttail;
+        }
+
+
+        /*************************************************************************
+        One-sample chi-square test
+
+        This test checks three hypotheses about the dispersion of the given sample
+        The following tests are performed:
+            * two-tailed test (null hypothesis - the dispersion equals  the  given
+              number)
+            * left-tailed test (null hypothesis - the dispersion is  greater  than
+              or equal to the given number)
+            * right-tailed test (null hypothesis  -  dispersion is  less  than  or
+              equal to the given number).
+
+        Test is based on the following assumptions:
+            * the given sample has a normal distribution.
+
+        Input parameters:
+            X           -   sample 1. Array whose index goes from 0 to N-1.
+            N           -   size of the sample.
+            Variance    -   dispersion value to compare with.
+
+        Output parameters:
+            BothTails   -   p-value for two-tailed test.
+                            If BothTails is less than the given significance level
+                            the null hypothesis is rejected.
+            LeftTail    -   p-value for left-tailed test.
+                            If LeftTail is less than the given significance level,
+                            the null hypothesis is rejected.
+            RightTail   -   p-value for right-tailed test.
+                            If RightTail is less than the given significance level
+                            the null hypothesis is rejected.
+
+          -- ALGLIB --
+             Copyright 19.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void onesamplevariancetest(ref double[] x,
+            int n,
+            double variance,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            double xmean = 0;
+            double ymean = 0;
+            double xvar = 0;
+            double yvar = 0;
+            double p = 0;
+            double s = 0;
+            double stat = 0;
+
+            if( n<=1 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Mean
+            //
+            xmean = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xmean = xmean+x[i];
+            }
+            xmean = xmean/n;
+            
+            //
+            // Variance
+            //
+            xvar = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                xvar = xvar+AP.Math.Sqr(x[i]-xmean);
+            }
+            xvar = xvar/(n-1);
+            if( (double)(xvar)==(double)(0) )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            
+            //
+            // Statistic
+            //
+            stat = (n-1)*xvar/variance;
+            s = chisquaredistr.chisquaredistribution(n-1, stat);
+            bothtails = 2*Math.Min(s, 1-s);
+            lefttail = s;
+            righttail = 1-lefttail;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/wsr.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/wsr.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/wsr.cs	(revision 2645)
@@ -0,0 +1,6249 @@
+/*************************************************************************
+Copyright (c) 2007, Sergey Bochkanov (ALGLIB project).
+
+>>> SOURCE LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the 
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
+>>> END OF LICENSE >>>
+*************************************************************************/
+
+using System;
+
+namespace alglib
+{
+    public class wsr
+    {
+        /*************************************************************************
+        Wilcoxon signed-rank test
+
+        This test checks three hypotheses about the median  of  the  given sample.
+        The following tests are performed:
+            * two-tailed test (null hypothesis - the median is equal to the  given
+              value)
+            * left-tailed test (null hypothesis - the median is  greater  than  or
+              equal to the given value)
+            * right-tailed test (null hypothesis  -  the  median  is  less than or
+              equal to the given value)
+
+        Requirements:
+            * the scale of measurement should be ordinal, interval or  ratio (i.e.
+              the test could not be applied to nominal variables).
+            * the distribution should be continuous and symmetric relative to  its
+              median.
+            * number of distinct values in the X array should be greater than 4
+
+        The test is non-parametric and doesn't require distribution X to be normal
+
+        Input parameters:
+            X       -   sample. Array whose index goes from 0 to N-1.
+            N       -   size of the sample.
+            Median  -   assumed median value.
+
+        Output parameters:
+            BothTails   -   p-value for two-tailed test.
+                            If BothTails is less than the given significance level
+                            the null hypothesis is rejected.
+            LeftTail    -   p-value for left-tailed test.
+                            If LeftTail is less than the given significance level,
+                            the null hypothesis is rejected.
+            RightTail   -   p-value for right-tailed test.
+                            If RightTail is less than the given significance level
+                            the null hypothesis is rejected.
+
+        To calculate p-values, special approximation is used. This method lets  us
+        calculate p-values with two decimal places in interval [0.0001, 1].
+
+        "Two decimal places" does not sound very impressive, but in  practice  the
+        relative error of less than 1% is enough to make a decision.
+
+        There is no approximation outside the [0.0001, 1] interval. Therefore,  if
+        the significance level outlies this interval, the test returns 0.0001.
+
+          -- ALGLIB --
+             Copyright 08.09.2006 by Bochkanov Sergey
+        *************************************************************************/
+        public static void wilcoxonsignedranktest(double[] x,
+            int n,
+            double e,
+            ref double bothtails,
+            ref double lefttail,
+            ref double righttail)
+        {
+            int i = 0;
+            int j = 0;
+            int k = 0;
+            int t = 0;
+            double tmp = 0;
+            int tmpi = 0;
+            int ns = 0;
+            double[] r = new double[0];
+            int[] c = new int[0];
+            double w = 0;
+            double p = 0;
+            double mp = 0;
+            double s = 0;
+            double sigma = 0;
+            double mu = 0;
+
+            x = (double[])x.Clone();
+
+            
+            //
+            // Prepare
+            //
+            if( n<5 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            ns = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                if( (double)(x[i])==(double)(e) )
+                {
+                    continue;
+                }
+                x[ns] = x[i];
+                ns = ns+1;
+            }
+            if( ns<5 )
+            {
+                bothtails = 1.0;
+                lefttail = 1.0;
+                righttail = 1.0;
+                return;
+            }
+            r = new double[ns-1+1];
+            c = new int[ns-1+1];
+            for(i=0; i<=ns-1; i++)
+            {
+                r[i] = Math.Abs(x[i]-e);
+                c[i] = i;
+            }
+            
+            //
+            // sort {R, C}
+            //
+            if( ns!=1 )
+            {
+                i = 2;
+                do
+                {
+                    t = i;
+                    while( t!=1 )
+                    {
+                        k = t/2;
+                        if( (double)(r[k-1])>=(double)(r[t-1]) )
+                        {
+                            t = 1;
+                        }
+                        else
+                        {
+                            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 = i+1;
+                }
+                while( i<=ns );
+                i = ns-1;
+                do
+                {
+                    tmp = r[i];
+                    r[i] = r[0];
+                    r[0] = tmp;
+                    tmpi = c[i];
+                    c[i] = c[0];
+                    c[0] = tmpi;
+                    t = 1;
+                    while( t!=0 )
+                    {
+                        k = 2*t;
+                        if( k>i )
+                        {
+                            t = 0;
+                        }
+                        else
+                        {
+                            if( k<i )
+                            {
+                                if( (double)(r[k])>(double)(r[k-1]) )
+                                {
+                                    k = k+1;
+                                }
+                            }
+                            if( (double)(r[t-1])>=(double)(r[k-1]) )
+                            {
+                                t = 0;
+                            }
+                            else
+                            {
+                                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 = i-1;
+                }
+                while( i>=1 );
+            }
+            
+            //
+            // compute tied ranks
+            //
+            i = 0;
+            while( i<=ns-1 )
+            {
+                j = i+1;
+                while( j<=ns-1 )
+                {
+                    if( (double)(r[j])!=(double)(r[i]) )
+                    {
+                        break;
+                    }
+                    j = j+1;
+                }
+                for(k=i; k<=j-1; k++)
+                {
+                    r[k] = 1+((double)(i+j-1))/(double)(2);
+                }
+                i = j;
+            }
+            
+            //
+            // Compute W+
+            //
+            w = 0;
+            for(i=0; i<=ns-1; i++)
+            {
+                if( (double)(x[c[i]])>(double)(e) )
+                {
+                    w = w+r[i];
+                }
+            }
+            
+            //
+            // Result
+            //
+            mu = (double)(ns*(ns+1))/(double)(4);
+            sigma = Math.Sqrt((double)(ns*(ns+1)*(2*ns+1))/(double)(24));
+            s = (w-mu)/sigma;
+            if( (double)(s)<=(double)(0) )
+            {
+                p = Math.Exp(wsigma(-((w-mu)/sigma), ns));
+                mp = 1-Math.Exp(wsigma(-((w-1-mu)/sigma), ns));
+            }
+            else
+            {
+                mp = Math.Exp(wsigma((w-mu)/sigma, ns));
+                p = 1-Math.Exp(wsigma((w+1-mu)/sigma, ns));
+            }
+            bothtails = Math.Max(2*Math.Min(p, mp), 1.0E-4);
+            lefttail = Math.Max(p, 1.0E-4);
+            righttail = Math.Max(mp, 1.0E-4);
+        }
+
+
+        /*************************************************************************
+        Sequential Chebyshev interpolation.
+        *************************************************************************/
+        private static void wcheb(double x,
+            double c,
+            ref double tj,
+            ref double tj1,
+            ref double r)
+        {
+            double t = 0;
+
+            r = r+c*tj;
+            t = 2*x*tj1-tj;
+            tj = tj1;
+            tj1 = t;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 5)
+        *************************************************************************/
+        private static double w5(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(3.708099e+00*s)+7.500000e+00);
+            if( w>=7 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==6 )
+            {
+                r = -9.008e-01;
+            }
+            if( w==5 )
+            {
+                r = -1.163e+00;
+            }
+            if( w==4 )
+            {
+                r = -1.520e+00;
+            }
+            if( w==3 )
+            {
+                r = -1.856e+00;
+            }
+            if( w==2 )
+            {
+                r = -2.367e+00;
+            }
+            if( w==1 )
+            {
+                r = -2.773e+00;
+            }
+            if( w<=0 )
+            {
+                r = -3.466e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 6)
+        *************************************************************************/
+        private static double w6(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(4.769696e+00*s)+1.050000e+01);
+            if( w>=10 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==9 )
+            {
+                r = -8.630e-01;
+            }
+            if( w==8 )
+            {
+                r = -1.068e+00;
+            }
+            if( w==7 )
+            {
+                r = -1.269e+00;
+            }
+            if( w==6 )
+            {
+                r = -1.520e+00;
+            }
+            if( w==5 )
+            {
+                r = -1.856e+00;
+            }
+            if( w==4 )
+            {
+                r = -2.213e+00;
+            }
+            if( w==3 )
+            {
+                r = -2.549e+00;
+            }
+            if( w==2 )
+            {
+                r = -3.060e+00;
+            }
+            if( w==1 )
+            {
+                r = -3.466e+00;
+            }
+            if( w<=0 )
+            {
+                r = -4.159e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 7)
+        *************************************************************************/
+        private static double w7(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(5.916080e+00*s)+1.400000e+01);
+            if( w>=14 )
+            {
+                r = -6.325e-01;
+            }
+            if( w==13 )
+            {
+                r = -7.577e-01;
+            }
+            if( w==12 )
+            {
+                r = -9.008e-01;
+            }
+            if( w==11 )
+            {
+                r = -1.068e+00;
+            }
+            if( w==10 )
+            {
+                r = -1.241e+00;
+            }
+            if( w==9 )
+            {
+                r = -1.451e+00;
+            }
+            if( w==8 )
+            {
+                r = -1.674e+00;
+            }
+            if( w==7 )
+            {
+                r = -1.908e+00;
+            }
+            if( w==6 )
+            {
+                r = -2.213e+00;
+            }
+            if( w==5 )
+            {
+                r = -2.549e+00;
+            }
+            if( w==4 )
+            {
+                r = -2.906e+00;
+            }
+            if( w==3 )
+            {
+                r = -3.243e+00;
+            }
+            if( w==2 )
+            {
+                r = -3.753e+00;
+            }
+            if( w==1 )
+            {
+                r = -4.159e+00;
+            }
+            if( w<=0 )
+            {
+                r = -4.852e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 8)
+        *************************************************************************/
+        private static double w8(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(7.141428e+00*s)+1.800000e+01);
+            if( w>=18 )
+            {
+                r = -6.399e-01;
+            }
+            if( w==17 )
+            {
+                r = -7.494e-01;
+            }
+            if( w==16 )
+            {
+                r = -8.630e-01;
+            }
+            if( w==15 )
+            {
+                r = -9.913e-01;
+            }
+            if( w==14 )
+            {
+                r = -1.138e+00;
+            }
+            if( w==13 )
+            {
+                r = -1.297e+00;
+            }
+            if( w==12 )
+            {
+                r = -1.468e+00;
+            }
+            if( w==11 )
+            {
+                r = -1.653e+00;
+            }
+            if( w==10 )
+            {
+                r = -1.856e+00;
+            }
+            if( w==9 )
+            {
+                r = -2.079e+00;
+            }
+            if( w==8 )
+            {
+                r = -2.326e+00;
+            }
+            if( w==7 )
+            {
+                r = -2.601e+00;
+            }
+            if( w==6 )
+            {
+                r = -2.906e+00;
+            }
+            if( w==5 )
+            {
+                r = -3.243e+00;
+            }
+            if( w==4 )
+            {
+                r = -3.599e+00;
+            }
+            if( w==3 )
+            {
+                r = -3.936e+00;
+            }
+            if( w==2 )
+            {
+                r = -4.447e+00;
+            }
+            if( w==1 )
+            {
+                r = -4.852e+00;
+            }
+            if( w<=0 )
+            {
+                r = -5.545e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 9)
+        *************************************************************************/
+        private static double w9(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(8.440972e+00*s)+2.250000e+01);
+            if( w>=22 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==21 )
+            {
+                r = -7.873e-01;
+            }
+            if( w==20 )
+            {
+                r = -8.912e-01;
+            }
+            if( w==19 )
+            {
+                r = -1.002e+00;
+            }
+            if( w==18 )
+            {
+                r = -1.120e+00;
+            }
+            if( w==17 )
+            {
+                r = -1.255e+00;
+            }
+            if( w==16 )
+            {
+                r = -1.394e+00;
+            }
+            if( w==15 )
+            {
+                r = -1.547e+00;
+            }
+            if( w==14 )
+            {
+                r = -1.717e+00;
+            }
+            if( w==13 )
+            {
+                r = -1.895e+00;
+            }
+            if( w==12 )
+            {
+                r = -2.079e+00;
+            }
+            if( w==11 )
+            {
+                r = -2.287e+00;
+            }
+            if( w==10 )
+            {
+                r = -2.501e+00;
+            }
+            if( w==9 )
+            {
+                r = -2.742e+00;
+            }
+            if( w==8 )
+            {
+                r = -3.019e+00;
+            }
+            if( w==7 )
+            {
+                r = -3.294e+00;
+            }
+            if( w==6 )
+            {
+                r = -3.599e+00;
+            }
+            if( w==5 )
+            {
+                r = -3.936e+00;
+            }
+            if( w==4 )
+            {
+                r = -4.292e+00;
+            }
+            if( w==3 )
+            {
+                r = -4.629e+00;
+            }
+            if( w==2 )
+            {
+                r = -5.140e+00;
+            }
+            if( w==1 )
+            {
+                r = -5.545e+00;
+            }
+            if( w<=0 )
+            {
+                r = -6.238e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 10)
+        *************************************************************************/
+        private static double w10(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(9.810708e+00*s)+2.750000e+01);
+            if( w>=27 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==26 )
+            {
+                r = -7.745e-01;
+            }
+            if( w==25 )
+            {
+                r = -8.607e-01;
+            }
+            if( w==24 )
+            {
+                r = -9.551e-01;
+            }
+            if( w==23 )
+            {
+                r = -1.057e+00;
+            }
+            if( w==22 )
+            {
+                r = -1.163e+00;
+            }
+            if( w==21 )
+            {
+                r = -1.279e+00;
+            }
+            if( w==20 )
+            {
+                r = -1.402e+00;
+            }
+            if( w==19 )
+            {
+                r = -1.533e+00;
+            }
+            if( w==18 )
+            {
+                r = -1.674e+00;
+            }
+            if( w==17 )
+            {
+                r = -1.826e+00;
+            }
+            if( w==16 )
+            {
+                r = -1.983e+00;
+            }
+            if( w==15 )
+            {
+                r = -2.152e+00;
+            }
+            if( w==14 )
+            {
+                r = -2.336e+00;
+            }
+            if( w==13 )
+            {
+                r = -2.525e+00;
+            }
+            if( w==12 )
+            {
+                r = -2.727e+00;
+            }
+            if( w==11 )
+            {
+                r = -2.942e+00;
+            }
+            if( w==10 )
+            {
+                r = -3.170e+00;
+            }
+            if( w==9 )
+            {
+                r = -3.435e+00;
+            }
+            if( w==8 )
+            {
+                r = -3.713e+00;
+            }
+            if( w==7 )
+            {
+                r = -3.987e+00;
+            }
+            if( w==6 )
+            {
+                r = -4.292e+00;
+            }
+            if( w==5 )
+            {
+                r = -4.629e+00;
+            }
+            if( w==4 )
+            {
+                r = -4.986e+00;
+            }
+            if( w==3 )
+            {
+                r = -5.322e+00;
+            }
+            if( w==2 )
+            {
+                r = -5.833e+00;
+            }
+            if( w==1 )
+            {
+                r = -6.238e+00;
+            }
+            if( w<=0 )
+            {
+                r = -6.931e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 11)
+        *************************************************************************/
+        private static double w11(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(1.124722e+01*s)+3.300000e+01);
+            if( w>=33 )
+            {
+                r = -6.595e-01;
+            }
+            if( w==32 )
+            {
+                r = -7.279e-01;
+            }
+            if( w==31 )
+            {
+                r = -8.002e-01;
+            }
+            if( w==30 )
+            {
+                r = -8.782e-01;
+            }
+            if( w==29 )
+            {
+                r = -9.615e-01;
+            }
+            if( w==28 )
+            {
+                r = -1.050e+00;
+            }
+            if( w==27 )
+            {
+                r = -1.143e+00;
+            }
+            if( w==26 )
+            {
+                r = -1.243e+00;
+            }
+            if( w==25 )
+            {
+                r = -1.348e+00;
+            }
+            if( w==24 )
+            {
+                r = -1.459e+00;
+            }
+            if( w==23 )
+            {
+                r = -1.577e+00;
+            }
+            if( w==22 )
+            {
+                r = -1.700e+00;
+            }
+            if( w==21 )
+            {
+                r = -1.832e+00;
+            }
+            if( w==20 )
+            {
+                r = -1.972e+00;
+            }
+            if( w==19 )
+            {
+                r = -2.119e+00;
+            }
+            if( w==18 )
+            {
+                r = -2.273e+00;
+            }
+            if( w==17 )
+            {
+                r = -2.437e+00;
+            }
+            if( w==16 )
+            {
+                r = -2.607e+00;
+            }
+            if( w==15 )
+            {
+                r = -2.788e+00;
+            }
+            if( w==14 )
+            {
+                r = -2.980e+00;
+            }
+            if( w==13 )
+            {
+                r = -3.182e+00;
+            }
+            if( w==12 )
+            {
+                r = -3.391e+00;
+            }
+            if( w==11 )
+            {
+                r = -3.617e+00;
+            }
+            if( w==10 )
+            {
+                r = -3.863e+00;
+            }
+            if( w==9 )
+            {
+                r = -4.128e+00;
+            }
+            if( w==8 )
+            {
+                r = -4.406e+00;
+            }
+            if( w==7 )
+            {
+                r = -4.680e+00;
+            }
+            if( w==6 )
+            {
+                r = -4.986e+00;
+            }
+            if( w==5 )
+            {
+                r = -5.322e+00;
+            }
+            if( w==4 )
+            {
+                r = -5.679e+00;
+            }
+            if( w==3 )
+            {
+                r = -6.015e+00;
+            }
+            if( w==2 )
+            {
+                r = -6.526e+00;
+            }
+            if( w==1 )
+            {
+                r = -6.931e+00;
+            }
+            if( w<=0 )
+            {
+                r = -7.625e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 12)
+        *************************************************************************/
+        private static double w12(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(1.274755e+01*s)+3.900000e+01);
+            if( w>=39 )
+            {
+                r = -6.633e-01;
+            }
+            if( w==38 )
+            {
+                r = -7.239e-01;
+            }
+            if( w==37 )
+            {
+                r = -7.878e-01;
+            }
+            if( w==36 )
+            {
+                r = -8.556e-01;
+            }
+            if( w==35 )
+            {
+                r = -9.276e-01;
+            }
+            if( w==34 )
+            {
+                r = -1.003e+00;
+            }
+            if( w==33 )
+            {
+                r = -1.083e+00;
+            }
+            if( w==32 )
+            {
+                r = -1.168e+00;
+            }
+            if( w==31 )
+            {
+                r = -1.256e+00;
+            }
+            if( w==30 )
+            {
+                r = -1.350e+00;
+            }
+            if( w==29 )
+            {
+                r = -1.449e+00;
+            }
+            if( w==28 )
+            {
+                r = -1.552e+00;
+            }
+            if( w==27 )
+            {
+                r = -1.660e+00;
+            }
+            if( w==26 )
+            {
+                r = -1.774e+00;
+            }
+            if( w==25 )
+            {
+                r = -1.893e+00;
+            }
+            if( w==24 )
+            {
+                r = -2.017e+00;
+            }
+            if( w==23 )
+            {
+                r = -2.148e+00;
+            }
+            if( w==22 )
+            {
+                r = -2.285e+00;
+            }
+            if( w==21 )
+            {
+                r = -2.429e+00;
+            }
+            if( w==20 )
+            {
+                r = -2.581e+00;
+            }
+            if( w==19 )
+            {
+                r = -2.738e+00;
+            }
+            if( w==18 )
+            {
+                r = -2.902e+00;
+            }
+            if( w==17 )
+            {
+                r = -3.076e+00;
+            }
+            if( w==16 )
+            {
+                r = -3.255e+00;
+            }
+            if( w==15 )
+            {
+                r = -3.443e+00;
+            }
+            if( w==14 )
+            {
+                r = -3.645e+00;
+            }
+            if( w==13 )
+            {
+                r = -3.852e+00;
+            }
+            if( w==12 )
+            {
+                r = -4.069e+00;
+            }
+            if( w==11 )
+            {
+                r = -4.310e+00;
+            }
+            if( w==10 )
+            {
+                r = -4.557e+00;
+            }
+            if( w==9 )
+            {
+                r = -4.821e+00;
+            }
+            if( w==8 )
+            {
+                r = -5.099e+00;
+            }
+            if( w==7 )
+            {
+                r = -5.373e+00;
+            }
+            if( w==6 )
+            {
+                r = -5.679e+00;
+            }
+            if( w==5 )
+            {
+                r = -6.015e+00;
+            }
+            if( w==4 )
+            {
+                r = -6.372e+00;
+            }
+            if( w==3 )
+            {
+                r = -6.708e+00;
+            }
+            if( w==2 )
+            {
+                r = -7.219e+00;
+            }
+            if( w==1 )
+            {
+                r = -7.625e+00;
+            }
+            if( w<=0 )
+            {
+                r = -8.318e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 13)
+        *************************************************************************/
+        private static double w13(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(1.430909e+01*s)+4.550000e+01);
+            if( w>=45 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==44 )
+            {
+                r = -7.486e-01;
+            }
+            if( w==43 )
+            {
+                r = -8.068e-01;
+            }
+            if( w==42 )
+            {
+                r = -8.683e-01;
+            }
+            if( w==41 )
+            {
+                r = -9.328e-01;
+            }
+            if( w==40 )
+            {
+                r = -1.001e+00;
+            }
+            if( w==39 )
+            {
+                r = -1.072e+00;
+            }
+            if( w==38 )
+            {
+                r = -1.146e+00;
+            }
+            if( w==37 )
+            {
+                r = -1.224e+00;
+            }
+            if( w==36 )
+            {
+                r = -1.306e+00;
+            }
+            if( w==35 )
+            {
+                r = -1.392e+00;
+            }
+            if( w==34 )
+            {
+                r = -1.481e+00;
+            }
+            if( w==33 )
+            {
+                r = -1.574e+00;
+            }
+            if( w==32 )
+            {
+                r = -1.672e+00;
+            }
+            if( w==31 )
+            {
+                r = -1.773e+00;
+            }
+            if( w==30 )
+            {
+                r = -1.879e+00;
+            }
+            if( w==29 )
+            {
+                r = -1.990e+00;
+            }
+            if( w==28 )
+            {
+                r = -2.104e+00;
+            }
+            if( w==27 )
+            {
+                r = -2.224e+00;
+            }
+            if( w==26 )
+            {
+                r = -2.349e+00;
+            }
+            if( w==25 )
+            {
+                r = -2.479e+00;
+            }
+            if( w==24 )
+            {
+                r = -2.614e+00;
+            }
+            if( w==23 )
+            {
+                r = -2.755e+00;
+            }
+            if( w==22 )
+            {
+                r = -2.902e+00;
+            }
+            if( w==21 )
+            {
+                r = -3.055e+00;
+            }
+            if( w==20 )
+            {
+                r = -3.215e+00;
+            }
+            if( w==19 )
+            {
+                r = -3.380e+00;
+            }
+            if( w==18 )
+            {
+                r = -3.551e+00;
+            }
+            if( w==17 )
+            {
+                r = -3.733e+00;
+            }
+            if( w==16 )
+            {
+                r = -3.917e+00;
+            }
+            if( w==15 )
+            {
+                r = -4.113e+00;
+            }
+            if( w==14 )
+            {
+                r = -4.320e+00;
+            }
+            if( w==13 )
+            {
+                r = -4.534e+00;
+            }
+            if( w==12 )
+            {
+                r = -4.762e+00;
+            }
+            if( w==11 )
+            {
+                r = -5.004e+00;
+            }
+            if( w==10 )
+            {
+                r = -5.250e+00;
+            }
+            if( w==9 )
+            {
+                r = -5.514e+00;
+            }
+            if( w==8 )
+            {
+                r = -5.792e+00;
+            }
+            if( w==7 )
+            {
+                r = -6.066e+00;
+            }
+            if( w==6 )
+            {
+                r = -6.372e+00;
+            }
+            if( w==5 )
+            {
+                r = -6.708e+00;
+            }
+            if( w==4 )
+            {
+                r = -7.065e+00;
+            }
+            if( w==3 )
+            {
+                r = -7.401e+00;
+            }
+            if( w==2 )
+            {
+                r = -7.912e+00;
+            }
+            if( w==1 )
+            {
+                r = -8.318e+00;
+            }
+            if( w<=0 )
+            {
+                r = -9.011e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 14)
+        *************************************************************************/
+        private static double w14(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(1.592953e+01*s)+5.250000e+01);
+            if( w>=52 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==51 )
+            {
+                r = -7.428e-01;
+            }
+            if( w==50 )
+            {
+                r = -7.950e-01;
+            }
+            if( w==49 )
+            {
+                r = -8.495e-01;
+            }
+            if( w==48 )
+            {
+                r = -9.067e-01;
+            }
+            if( w==47 )
+            {
+                r = -9.664e-01;
+            }
+            if( w==46 )
+            {
+                r = -1.029e+00;
+            }
+            if( w==45 )
+            {
+                r = -1.094e+00;
+            }
+            if( w==44 )
+            {
+                r = -1.162e+00;
+            }
+            if( w==43 )
+            {
+                r = -1.233e+00;
+            }
+            if( w==42 )
+            {
+                r = -1.306e+00;
+            }
+            if( w==41 )
+            {
+                r = -1.383e+00;
+            }
+            if( w==40 )
+            {
+                r = -1.463e+00;
+            }
+            if( w==39 )
+            {
+                r = -1.546e+00;
+            }
+            if( w==38 )
+            {
+                r = -1.632e+00;
+            }
+            if( w==37 )
+            {
+                r = -1.722e+00;
+            }
+            if( w==36 )
+            {
+                r = -1.815e+00;
+            }
+            if( w==35 )
+            {
+                r = -1.911e+00;
+            }
+            if( w==34 )
+            {
+                r = -2.011e+00;
+            }
+            if( w==33 )
+            {
+                r = -2.115e+00;
+            }
+            if( w==32 )
+            {
+                r = -2.223e+00;
+            }
+            if( w==31 )
+            {
+                r = -2.334e+00;
+            }
+            if( w==30 )
+            {
+                r = -2.450e+00;
+            }
+            if( w==29 )
+            {
+                r = -2.570e+00;
+            }
+            if( w==28 )
+            {
+                r = -2.694e+00;
+            }
+            if( w==27 )
+            {
+                r = -2.823e+00;
+            }
+            if( w==26 )
+            {
+                r = -2.956e+00;
+            }
+            if( w==25 )
+            {
+                r = -3.095e+00;
+            }
+            if( w==24 )
+            {
+                r = -3.238e+00;
+            }
+            if( w==23 )
+            {
+                r = -3.387e+00;
+            }
+            if( w==22 )
+            {
+                r = -3.541e+00;
+            }
+            if( w==21 )
+            {
+                r = -3.700e+00;
+            }
+            if( w==20 )
+            {
+                r = -3.866e+00;
+            }
+            if( w==19 )
+            {
+                r = -4.038e+00;
+            }
+            if( w==18 )
+            {
+                r = -4.215e+00;
+            }
+            if( w==17 )
+            {
+                r = -4.401e+00;
+            }
+            if( w==16 )
+            {
+                r = -4.592e+00;
+            }
+            if( w==15 )
+            {
+                r = -4.791e+00;
+            }
+            if( w==14 )
+            {
+                r = -5.004e+00;
+            }
+            if( w==13 )
+            {
+                r = -5.227e+00;
+            }
+            if( w==12 )
+            {
+                r = -5.456e+00;
+            }
+            if( w==11 )
+            {
+                r = -5.697e+00;
+            }
+            if( w==10 )
+            {
+                r = -5.943e+00;
+            }
+            if( w==9 )
+            {
+                r = -6.208e+00;
+            }
+            if( w==8 )
+            {
+                r = -6.485e+00;
+            }
+            if( w==7 )
+            {
+                r = -6.760e+00;
+            }
+            if( w==6 )
+            {
+                r = -7.065e+00;
+            }
+            if( w==5 )
+            {
+                r = -7.401e+00;
+            }
+            if( w==4 )
+            {
+                r = -7.758e+00;
+            }
+            if( w==3 )
+            {
+                r = -8.095e+00;
+            }
+            if( w==2 )
+            {
+                r = -8.605e+00;
+            }
+            if( w==1 )
+            {
+                r = -9.011e+00;
+            }
+            if( w<=0 )
+            {
+                r = -9.704e+00;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 15)
+        *************************************************************************/
+        private static double w15(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(1.760682e+01*s)+6.000000e+01);
+            if( w>=60 )
+            {
+                r = -6.714e-01;
+            }
+            if( w==59 )
+            {
+                r = -7.154e-01;
+            }
+            if( w==58 )
+            {
+                r = -7.613e-01;
+            }
+            if( w==57 )
+            {
+                r = -8.093e-01;
+            }
+            if( w==56 )
+            {
+                r = -8.593e-01;
+            }
+            if( w==55 )
+            {
+                r = -9.114e-01;
+            }
+            if( w==54 )
+            {
+                r = -9.656e-01;
+            }
+            if( w==53 )
+            {
+                r = -1.022e+00;
+            }
+            if( w==52 )
+            {
+                r = -1.081e+00;
+            }
+            if( w==51 )
+            {
+                r = -1.142e+00;
+            }
+            if( w==50 )
+            {
+                r = -1.205e+00;
+            }
+            if( w==49 )
+            {
+                r = -1.270e+00;
+            }
+            if( w==48 )
+            {
+                r = -1.339e+00;
+            }
+            if( w==47 )
+            {
+                r = -1.409e+00;
+            }
+            if( w==46 )
+            {
+                r = -1.482e+00;
+            }
+            if( w==45 )
+            {
+                r = -1.558e+00;
+            }
+            if( w==44 )
+            {
+                r = -1.636e+00;
+            }
+            if( w==43 )
+            {
+                r = -1.717e+00;
+            }
+            if( w==42 )
+            {
+                r = -1.801e+00;
+            }
+            if( w==41 )
+            {
+                r = -1.888e+00;
+            }
+            if( w==40 )
+            {
+                r = -1.977e+00;
+            }
+            if( w==39 )
+            {
+                r = -2.070e+00;
+            }
+            if( w==38 )
+            {
+                r = -2.166e+00;
+            }
+            if( w==37 )
+            {
+                r = -2.265e+00;
+            }
+            if( w==36 )
+            {
+                r = -2.366e+00;
+            }
+            if( w==35 )
+            {
+                r = -2.472e+00;
+            }
+            if( w==34 )
+            {
+                r = -2.581e+00;
+            }
+            if( w==33 )
+            {
+                r = -2.693e+00;
+            }
+            if( w==32 )
+            {
+                r = -2.809e+00;
+            }
+            if( w==31 )
+            {
+                r = -2.928e+00;
+            }
+            if( w==30 )
+            {
+                r = -3.051e+00;
+            }
+            if( w==29 )
+            {
+                r = -3.179e+00;
+            }
+            if( w==28 )
+            {
+                r = -3.310e+00;
+            }
+            if( w==27 )
+            {
+                r = -3.446e+00;
+            }
+            if( w==26 )
+            {
+                r = -3.587e+00;
+            }
+            if( w==25 )
+            {
+                r = -3.732e+00;
+            }
+            if( w==24 )
+            {
+                r = -3.881e+00;
+            }
+            if( w==23 )
+            {
+                r = -4.036e+00;
+            }
+            if( w==22 )
+            {
+                r = -4.195e+00;
+            }
+            if( w==21 )
+            {
+                r = -4.359e+00;
+            }
+            if( w==20 )
+            {
+                r = -4.531e+00;
+            }
+            if( w==19 )
+            {
+                r = -4.707e+00;
+            }
+            if( w==18 )
+            {
+                r = -4.888e+00;
+            }
+            if( w==17 )
+            {
+                r = -5.079e+00;
+            }
+            if( w==16 )
+            {
+                r = -5.273e+00;
+            }
+            if( w==15 )
+            {
+                r = -5.477e+00;
+            }
+            if( w==14 )
+            {
+                r = -5.697e+00;
+            }
+            if( w==13 )
+            {
+                r = -5.920e+00;
+            }
+            if( w==12 )
+            {
+                r = -6.149e+00;
+            }
+            if( w==11 )
+            {
+                r = -6.390e+00;
+            }
+            if( w==10 )
+            {
+                r = -6.636e+00;
+            }
+            if( w==9 )
+            {
+                r = -6.901e+00;
+            }
+            if( w==8 )
+            {
+                r = -7.178e+00;
+            }
+            if( w==7 )
+            {
+                r = -7.453e+00;
+            }
+            if( w==6 )
+            {
+                r = -7.758e+00;
+            }
+            if( w==5 )
+            {
+                r = -8.095e+00;
+            }
+            if( w==4 )
+            {
+                r = -8.451e+00;
+            }
+            if( w==3 )
+            {
+                r = -8.788e+00;
+            }
+            if( w==2 )
+            {
+                r = -9.299e+00;
+            }
+            if( w==1 )
+            {
+                r = -9.704e+00;
+            }
+            if( w<=0 )
+            {
+                r = -1.040e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 16)
+        *************************************************************************/
+        private static double w16(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(1.933908e+01*s)+6.800000e+01);
+            if( w>=68 )
+            {
+                r = -6.733e-01;
+            }
+            if( w==67 )
+            {
+                r = -7.134e-01;
+            }
+            if( w==66 )
+            {
+                r = -7.551e-01;
+            }
+            if( w==65 )
+            {
+                r = -7.986e-01;
+            }
+            if( w==64 )
+            {
+                r = -8.437e-01;
+            }
+            if( w==63 )
+            {
+                r = -8.905e-01;
+            }
+            if( w==62 )
+            {
+                r = -9.391e-01;
+            }
+            if( w==61 )
+            {
+                r = -9.895e-01;
+            }
+            if( w==60 )
+            {
+                r = -1.042e+00;
+            }
+            if( w==59 )
+            {
+                r = -1.096e+00;
+            }
+            if( w==58 )
+            {
+                r = -1.152e+00;
+            }
+            if( w==57 )
+            {
+                r = -1.210e+00;
+            }
+            if( w==56 )
+            {
+                r = -1.270e+00;
+            }
+            if( w==55 )
+            {
+                r = -1.331e+00;
+            }
+            if( w==54 )
+            {
+                r = -1.395e+00;
+            }
+            if( w==53 )
+            {
+                r = -1.462e+00;
+            }
+            if( w==52 )
+            {
+                r = -1.530e+00;
+            }
+            if( w==51 )
+            {
+                r = -1.600e+00;
+            }
+            if( w==50 )
+            {
+                r = -1.673e+00;
+            }
+            if( w==49 )
+            {
+                r = -1.748e+00;
+            }
+            if( w==48 )
+            {
+                r = -1.825e+00;
+            }
+            if( w==47 )
+            {
+                r = -1.904e+00;
+            }
+            if( w==46 )
+            {
+                r = -1.986e+00;
+            }
+            if( w==45 )
+            {
+                r = -2.071e+00;
+            }
+            if( w==44 )
+            {
+                r = -2.158e+00;
+            }
+            if( w==43 )
+            {
+                r = -2.247e+00;
+            }
+            if( w==42 )
+            {
+                r = -2.339e+00;
+            }
+            if( w==41 )
+            {
+                r = -2.434e+00;
+            }
+            if( w==40 )
+            {
+                r = -2.532e+00;
+            }
+            if( w==39 )
+            {
+                r = -2.632e+00;
+            }
+            if( w==38 )
+            {
+                r = -2.735e+00;
+            }
+            if( w==37 )
+            {
+                r = -2.842e+00;
+            }
+            if( w==36 )
+            {
+                r = -2.951e+00;
+            }
+            if( w==35 )
+            {
+                r = -3.064e+00;
+            }
+            if( w==34 )
+            {
+                r = -3.179e+00;
+            }
+            if( w==33 )
+            {
+                r = -3.298e+00;
+            }
+            if( w==32 )
+            {
+                r = -3.420e+00;
+            }
+            if( w==31 )
+            {
+                r = -3.546e+00;
+            }
+            if( w==30 )
+            {
+                r = -3.676e+00;
+            }
+            if( w==29 )
+            {
+                r = -3.810e+00;
+            }
+            if( w==28 )
+            {
+                r = -3.947e+00;
+            }
+            if( w==27 )
+            {
+                r = -4.088e+00;
+            }
+            if( w==26 )
+            {
+                r = -4.234e+00;
+            }
+            if( w==25 )
+            {
+                r = -4.383e+00;
+            }
+            if( w==24 )
+            {
+                r = -4.538e+00;
+            }
+            if( w==23 )
+            {
+                r = -4.697e+00;
+            }
+            if( w==22 )
+            {
+                r = -4.860e+00;
+            }
+            if( w==21 )
+            {
+                r = -5.029e+00;
+            }
+            if( w==20 )
+            {
+                r = -5.204e+00;
+            }
+            if( w==19 )
+            {
+                r = -5.383e+00;
+            }
+            if( w==18 )
+            {
+                r = -5.569e+00;
+            }
+            if( w==17 )
+            {
+                r = -5.762e+00;
+            }
+            if( w==16 )
+            {
+                r = -5.960e+00;
+            }
+            if( w==15 )
+            {
+                r = -6.170e+00;
+            }
+            if( w==14 )
+            {
+                r = -6.390e+00;
+            }
+            if( w==13 )
+            {
+                r = -6.613e+00;
+            }
+            if( w==12 )
+            {
+                r = -6.842e+00;
+            }
+            if( w==11 )
+            {
+                r = -7.083e+00;
+            }
+            if( w==10 )
+            {
+                r = -7.329e+00;
+            }
+            if( w==9 )
+            {
+                r = -7.594e+00;
+            }
+            if( w==8 )
+            {
+                r = -7.871e+00;
+            }
+            if( w==7 )
+            {
+                r = -8.146e+00;
+            }
+            if( w==6 )
+            {
+                r = -8.451e+00;
+            }
+            if( w==5 )
+            {
+                r = -8.788e+00;
+            }
+            if( w==4 )
+            {
+                r = -9.144e+00;
+            }
+            if( w==3 )
+            {
+                r = -9.481e+00;
+            }
+            if( w==2 )
+            {
+                r = -9.992e+00;
+            }
+            if( w==1 )
+            {
+                r = -1.040e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.109e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 17)
+        *************************************************************************/
+        private static double w17(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(2.112463e+01*s)+7.650000e+01);
+            if( w>=76 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==75 )
+            {
+                r = -7.306e-01;
+            }
+            if( w==74 )
+            {
+                r = -7.695e-01;
+            }
+            if( w==73 )
+            {
+                r = -8.097e-01;
+            }
+            if( w==72 )
+            {
+                r = -8.514e-01;
+            }
+            if( w==71 )
+            {
+                r = -8.946e-01;
+            }
+            if( w==70 )
+            {
+                r = -9.392e-01;
+            }
+            if( w==69 )
+            {
+                r = -9.853e-01;
+            }
+            if( w==68 )
+            {
+                r = -1.033e+00;
+            }
+            if( w==67 )
+            {
+                r = -1.082e+00;
+            }
+            if( w==66 )
+            {
+                r = -1.133e+00;
+            }
+            if( w==65 )
+            {
+                r = -1.185e+00;
+            }
+            if( w==64 )
+            {
+                r = -1.240e+00;
+            }
+            if( w==63 )
+            {
+                r = -1.295e+00;
+            }
+            if( w==62 )
+            {
+                r = -1.353e+00;
+            }
+            if( w==61 )
+            {
+                r = -1.412e+00;
+            }
+            if( w==60 )
+            {
+                r = -1.473e+00;
+            }
+            if( w==59 )
+            {
+                r = -1.536e+00;
+            }
+            if( w==58 )
+            {
+                r = -1.600e+00;
+            }
+            if( w==57 )
+            {
+                r = -1.666e+00;
+            }
+            if( w==56 )
+            {
+                r = -1.735e+00;
+            }
+            if( w==55 )
+            {
+                r = -1.805e+00;
+            }
+            if( w==54 )
+            {
+                r = -1.877e+00;
+            }
+            if( w==53 )
+            {
+                r = -1.951e+00;
+            }
+            if( w==52 )
+            {
+                r = -2.028e+00;
+            }
+            if( w==51 )
+            {
+                r = -2.106e+00;
+            }
+            if( w==50 )
+            {
+                r = -2.186e+00;
+            }
+            if( w==49 )
+            {
+                r = -2.269e+00;
+            }
+            if( w==48 )
+            {
+                r = -2.353e+00;
+            }
+            if( w==47 )
+            {
+                r = -2.440e+00;
+            }
+            if( w==46 )
+            {
+                r = -2.530e+00;
+            }
+            if( w==45 )
+            {
+                r = -2.621e+00;
+            }
+            if( w==44 )
+            {
+                r = -2.715e+00;
+            }
+            if( w==43 )
+            {
+                r = -2.812e+00;
+            }
+            if( w==42 )
+            {
+                r = -2.911e+00;
+            }
+            if( w==41 )
+            {
+                r = -3.012e+00;
+            }
+            if( w==40 )
+            {
+                r = -3.116e+00;
+            }
+            if( w==39 )
+            {
+                r = -3.223e+00;
+            }
+            if( w==38 )
+            {
+                r = -3.332e+00;
+            }
+            if( w==37 )
+            {
+                r = -3.445e+00;
+            }
+            if( w==36 )
+            {
+                r = -3.560e+00;
+            }
+            if( w==35 )
+            {
+                r = -3.678e+00;
+            }
+            if( w==34 )
+            {
+                r = -3.799e+00;
+            }
+            if( w==33 )
+            {
+                r = -3.924e+00;
+            }
+            if( w==32 )
+            {
+                r = -4.052e+00;
+            }
+            if( w==31 )
+            {
+                r = -4.183e+00;
+            }
+            if( w==30 )
+            {
+                r = -4.317e+00;
+            }
+            if( w==29 )
+            {
+                r = -4.456e+00;
+            }
+            if( w==28 )
+            {
+                r = -4.597e+00;
+            }
+            if( w==27 )
+            {
+                r = -4.743e+00;
+            }
+            if( w==26 )
+            {
+                r = -4.893e+00;
+            }
+            if( w==25 )
+            {
+                r = -5.047e+00;
+            }
+            if( w==24 )
+            {
+                r = -5.204e+00;
+            }
+            if( w==23 )
+            {
+                r = -5.367e+00;
+            }
+            if( w==22 )
+            {
+                r = -5.534e+00;
+            }
+            if( w==21 )
+            {
+                r = -5.706e+00;
+            }
+            if( w==20 )
+            {
+                r = -5.884e+00;
+            }
+            if( w==19 )
+            {
+                r = -6.066e+00;
+            }
+            if( w==18 )
+            {
+                r = -6.254e+00;
+            }
+            if( w==17 )
+            {
+                r = -6.451e+00;
+            }
+            if( w==16 )
+            {
+                r = -6.654e+00;
+            }
+            if( w==15 )
+            {
+                r = -6.864e+00;
+            }
+            if( w==14 )
+            {
+                r = -7.083e+00;
+            }
+            if( w==13 )
+            {
+                r = -7.306e+00;
+            }
+            if( w==12 )
+            {
+                r = -7.535e+00;
+            }
+            if( w==11 )
+            {
+                r = -7.776e+00;
+            }
+            if( w==10 )
+            {
+                r = -8.022e+00;
+            }
+            if( w==9 )
+            {
+                r = -8.287e+00;
+            }
+            if( w==8 )
+            {
+                r = -8.565e+00;
+            }
+            if( w==7 )
+            {
+                r = -8.839e+00;
+            }
+            if( w==6 )
+            {
+                r = -9.144e+00;
+            }
+            if( w==5 )
+            {
+                r = -9.481e+00;
+            }
+            if( w==4 )
+            {
+                r = -9.838e+00;
+            }
+            if( w==3 )
+            {
+                r = -1.017e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.068e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.109e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.178e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 18)
+        *************************************************************************/
+        private static double w18(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(2.296193e+01*s)+8.550000e+01);
+            if( w>=85 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==84 )
+            {
+                r = -7.276e-01;
+            }
+            if( w==83 )
+            {
+                r = -7.633e-01;
+            }
+            if( w==82 )
+            {
+                r = -8.001e-01;
+            }
+            if( w==81 )
+            {
+                r = -8.381e-01;
+            }
+            if( w==80 )
+            {
+                r = -8.774e-01;
+            }
+            if( w==79 )
+            {
+                r = -9.179e-01;
+            }
+            if( w==78 )
+            {
+                r = -9.597e-01;
+            }
+            if( w==77 )
+            {
+                r = -1.003e+00;
+            }
+            if( w==76 )
+            {
+                r = -1.047e+00;
+            }
+            if( w==75 )
+            {
+                r = -1.093e+00;
+            }
+            if( w==74 )
+            {
+                r = -1.140e+00;
+            }
+            if( w==73 )
+            {
+                r = -1.188e+00;
+            }
+            if( w==72 )
+            {
+                r = -1.238e+00;
+            }
+            if( w==71 )
+            {
+                r = -1.289e+00;
+            }
+            if( w==70 )
+            {
+                r = -1.342e+00;
+            }
+            if( w==69 )
+            {
+                r = -1.396e+00;
+            }
+            if( w==68 )
+            {
+                r = -1.452e+00;
+            }
+            if( w==67 )
+            {
+                r = -1.509e+00;
+            }
+            if( w==66 )
+            {
+                r = -1.568e+00;
+            }
+            if( w==65 )
+            {
+                r = -1.628e+00;
+            }
+            if( w==64 )
+            {
+                r = -1.690e+00;
+            }
+            if( w==63 )
+            {
+                r = -1.753e+00;
+            }
+            if( w==62 )
+            {
+                r = -1.818e+00;
+            }
+            if( w==61 )
+            {
+                r = -1.885e+00;
+            }
+            if( w==60 )
+            {
+                r = -1.953e+00;
+            }
+            if( w==59 )
+            {
+                r = -2.023e+00;
+            }
+            if( w==58 )
+            {
+                r = -2.095e+00;
+            }
+            if( w==57 )
+            {
+                r = -2.168e+00;
+            }
+            if( w==56 )
+            {
+                r = -2.244e+00;
+            }
+            if( w==55 )
+            {
+                r = -2.321e+00;
+            }
+            if( w==54 )
+            {
+                r = -2.400e+00;
+            }
+            if( w==53 )
+            {
+                r = -2.481e+00;
+            }
+            if( w==52 )
+            {
+                r = -2.564e+00;
+            }
+            if( w==51 )
+            {
+                r = -2.648e+00;
+            }
+            if( w==50 )
+            {
+                r = -2.735e+00;
+            }
+            if( w==49 )
+            {
+                r = -2.824e+00;
+            }
+            if( w==48 )
+            {
+                r = -2.915e+00;
+            }
+            if( w==47 )
+            {
+                r = -3.008e+00;
+            }
+            if( w==46 )
+            {
+                r = -3.104e+00;
+            }
+            if( w==45 )
+            {
+                r = -3.201e+00;
+            }
+            if( w==44 )
+            {
+                r = -3.301e+00;
+            }
+            if( w==43 )
+            {
+                r = -3.403e+00;
+            }
+            if( w==42 )
+            {
+                r = -3.508e+00;
+            }
+            if( w==41 )
+            {
+                r = -3.615e+00;
+            }
+            if( w==40 )
+            {
+                r = -3.724e+00;
+            }
+            if( w==39 )
+            {
+                r = -3.836e+00;
+            }
+            if( w==38 )
+            {
+                r = -3.950e+00;
+            }
+            if( w==37 )
+            {
+                r = -4.068e+00;
+            }
+            if( w==36 )
+            {
+                r = -4.188e+00;
+            }
+            if( w==35 )
+            {
+                r = -4.311e+00;
+            }
+            if( w==34 )
+            {
+                r = -4.437e+00;
+            }
+            if( w==33 )
+            {
+                r = -4.565e+00;
+            }
+            if( w==32 )
+            {
+                r = -4.698e+00;
+            }
+            if( w==31 )
+            {
+                r = -4.833e+00;
+            }
+            if( w==30 )
+            {
+                r = -4.971e+00;
+            }
+            if( w==29 )
+            {
+                r = -5.113e+00;
+            }
+            if( w==28 )
+            {
+                r = -5.258e+00;
+            }
+            if( w==27 )
+            {
+                r = -5.408e+00;
+            }
+            if( w==26 )
+            {
+                r = -5.561e+00;
+            }
+            if( w==25 )
+            {
+                r = -5.717e+00;
+            }
+            if( w==24 )
+            {
+                r = -5.878e+00;
+            }
+            if( w==23 )
+            {
+                r = -6.044e+00;
+            }
+            if( w==22 )
+            {
+                r = -6.213e+00;
+            }
+            if( w==21 )
+            {
+                r = -6.388e+00;
+            }
+            if( w==20 )
+            {
+                r = -6.569e+00;
+            }
+            if( w==19 )
+            {
+                r = -6.753e+00;
+            }
+            if( w==18 )
+            {
+                r = -6.943e+00;
+            }
+            if( w==17 )
+            {
+                r = -7.144e+00;
+            }
+            if( w==16 )
+            {
+                r = -7.347e+00;
+            }
+            if( w==15 )
+            {
+                r = -7.557e+00;
+            }
+            if( w==14 )
+            {
+                r = -7.776e+00;
+            }
+            if( w==13 )
+            {
+                r = -7.999e+00;
+            }
+            if( w==12 )
+            {
+                r = -8.228e+00;
+            }
+            if( w==11 )
+            {
+                r = -8.469e+00;
+            }
+            if( w==10 )
+            {
+                r = -8.715e+00;
+            }
+            if( w==9 )
+            {
+                r = -8.980e+00;
+            }
+            if( w==8 )
+            {
+                r = -9.258e+00;
+            }
+            if( w==7 )
+            {
+                r = -9.532e+00;
+            }
+            if( w==6 )
+            {
+                r = -9.838e+00;
+            }
+            if( w==5 )
+            {
+                r = -1.017e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.053e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.087e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.138e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.178e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.248e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 19)
+        *************************************************************************/
+        private static double w19(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(2.484955e+01*s)+9.500000e+01);
+            if( w>=95 )
+            {
+                r = -6.776e-01;
+            }
+            if( w==94 )
+            {
+                r = -7.089e-01;
+            }
+            if( w==93 )
+            {
+                r = -7.413e-01;
+            }
+            if( w==92 )
+            {
+                r = -7.747e-01;
+            }
+            if( w==91 )
+            {
+                r = -8.090e-01;
+            }
+            if( w==90 )
+            {
+                r = -8.445e-01;
+            }
+            if( w==89 )
+            {
+                r = -8.809e-01;
+            }
+            if( w==88 )
+            {
+                r = -9.185e-01;
+            }
+            if( w==87 )
+            {
+                r = -9.571e-01;
+            }
+            if( w==86 )
+            {
+                r = -9.968e-01;
+            }
+            if( w==85 )
+            {
+                r = -1.038e+00;
+            }
+            if( w==84 )
+            {
+                r = -1.080e+00;
+            }
+            if( w==83 )
+            {
+                r = -1.123e+00;
+            }
+            if( w==82 )
+            {
+                r = -1.167e+00;
+            }
+            if( w==81 )
+            {
+                r = -1.213e+00;
+            }
+            if( w==80 )
+            {
+                r = -1.259e+00;
+            }
+            if( w==79 )
+            {
+                r = -1.307e+00;
+            }
+            if( w==78 )
+            {
+                r = -1.356e+00;
+            }
+            if( w==77 )
+            {
+                r = -1.407e+00;
+            }
+            if( w==76 )
+            {
+                r = -1.458e+00;
+            }
+            if( w==75 )
+            {
+                r = -1.511e+00;
+            }
+            if( w==74 )
+            {
+                r = -1.565e+00;
+            }
+            if( w==73 )
+            {
+                r = -1.621e+00;
+            }
+            if( w==72 )
+            {
+                r = -1.678e+00;
+            }
+            if( w==71 )
+            {
+                r = -1.736e+00;
+            }
+            if( w==70 )
+            {
+                r = -1.796e+00;
+            }
+            if( w==69 )
+            {
+                r = -1.857e+00;
+            }
+            if( w==68 )
+            {
+                r = -1.919e+00;
+            }
+            if( w==67 )
+            {
+                r = -1.983e+00;
+            }
+            if( w==66 )
+            {
+                r = -2.048e+00;
+            }
+            if( w==65 )
+            {
+                r = -2.115e+00;
+            }
+            if( w==64 )
+            {
+                r = -2.183e+00;
+            }
+            if( w==63 )
+            {
+                r = -2.253e+00;
+            }
+            if( w==62 )
+            {
+                r = -2.325e+00;
+            }
+            if( w==61 )
+            {
+                r = -2.398e+00;
+            }
+            if( w==60 )
+            {
+                r = -2.472e+00;
+            }
+            if( w==59 )
+            {
+                r = -2.548e+00;
+            }
+            if( w==58 )
+            {
+                r = -2.626e+00;
+            }
+            if( w==57 )
+            {
+                r = -2.706e+00;
+            }
+            if( w==56 )
+            {
+                r = -2.787e+00;
+            }
+            if( w==55 )
+            {
+                r = -2.870e+00;
+            }
+            if( w==54 )
+            {
+                r = -2.955e+00;
+            }
+            if( w==53 )
+            {
+                r = -3.042e+00;
+            }
+            if( w==52 )
+            {
+                r = -3.130e+00;
+            }
+            if( w==51 )
+            {
+                r = -3.220e+00;
+            }
+            if( w==50 )
+            {
+                r = -3.313e+00;
+            }
+            if( w==49 )
+            {
+                r = -3.407e+00;
+            }
+            if( w==48 )
+            {
+                r = -3.503e+00;
+            }
+            if( w==47 )
+            {
+                r = -3.601e+00;
+            }
+            if( w==46 )
+            {
+                r = -3.702e+00;
+            }
+            if( w==45 )
+            {
+                r = -3.804e+00;
+            }
+            if( w==44 )
+            {
+                r = -3.909e+00;
+            }
+            if( w==43 )
+            {
+                r = -4.015e+00;
+            }
+            if( w==42 )
+            {
+                r = -4.125e+00;
+            }
+            if( w==41 )
+            {
+                r = -4.236e+00;
+            }
+            if( w==40 )
+            {
+                r = -4.350e+00;
+            }
+            if( w==39 )
+            {
+                r = -4.466e+00;
+            }
+            if( w==38 )
+            {
+                r = -4.585e+00;
+            }
+            if( w==37 )
+            {
+                r = -4.706e+00;
+            }
+            if( w==36 )
+            {
+                r = -4.830e+00;
+            }
+            if( w==35 )
+            {
+                r = -4.957e+00;
+            }
+            if( w==34 )
+            {
+                r = -5.086e+00;
+            }
+            if( w==33 )
+            {
+                r = -5.219e+00;
+            }
+            if( w==32 )
+            {
+                r = -5.355e+00;
+            }
+            if( w==31 )
+            {
+                r = -5.493e+00;
+            }
+            if( w==30 )
+            {
+                r = -5.634e+00;
+            }
+            if( w==29 )
+            {
+                r = -5.780e+00;
+            }
+            if( w==28 )
+            {
+                r = -5.928e+00;
+            }
+            if( w==27 )
+            {
+                r = -6.080e+00;
+            }
+            if( w==26 )
+            {
+                r = -6.235e+00;
+            }
+            if( w==25 )
+            {
+                r = -6.394e+00;
+            }
+            if( w==24 )
+            {
+                r = -6.558e+00;
+            }
+            if( w==23 )
+            {
+                r = -6.726e+00;
+            }
+            if( w==22 )
+            {
+                r = -6.897e+00;
+            }
+            if( w==21 )
+            {
+                r = -7.074e+00;
+            }
+            if( w==20 )
+            {
+                r = -7.256e+00;
+            }
+            if( w==19 )
+            {
+                r = -7.443e+00;
+            }
+            if( w==18 )
+            {
+                r = -7.636e+00;
+            }
+            if( w==17 )
+            {
+                r = -7.837e+00;
+            }
+            if( w==16 )
+            {
+                r = -8.040e+00;
+            }
+            if( w==15 )
+            {
+                r = -8.250e+00;
+            }
+            if( w==14 )
+            {
+                r = -8.469e+00;
+            }
+            if( w==13 )
+            {
+                r = -8.692e+00;
+            }
+            if( w==12 )
+            {
+                r = -8.921e+00;
+            }
+            if( w==11 )
+            {
+                r = -9.162e+00;
+            }
+            if( w==10 )
+            {
+                r = -9.409e+00;
+            }
+            if( w==9 )
+            {
+                r = -9.673e+00;
+            }
+            if( w==8 )
+            {
+                r = -9.951e+00;
+            }
+            if( w==7 )
+            {
+                r = -1.023e+01;
+            }
+            if( w==6 )
+            {
+                r = -1.053e+01;
+            }
+            if( w==5 )
+            {
+                r = -1.087e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.122e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.156e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.207e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.248e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.317e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 20)
+        *************************************************************************/
+        private static double w20(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(2.678619e+01*s)+1.050000e+02);
+            if( w>=105 )
+            {
+                r = -6.787e-01;
+            }
+            if( w==104 )
+            {
+                r = -7.078e-01;
+            }
+            if( w==103 )
+            {
+                r = -7.378e-01;
+            }
+            if( w==102 )
+            {
+                r = -7.686e-01;
+            }
+            if( w==101 )
+            {
+                r = -8.004e-01;
+            }
+            if( w==100 )
+            {
+                r = -8.330e-01;
+            }
+            if( w==99 )
+            {
+                r = -8.665e-01;
+            }
+            if( w==98 )
+            {
+                r = -9.010e-01;
+            }
+            if( w==97 )
+            {
+                r = -9.363e-01;
+            }
+            if( w==96 )
+            {
+                r = -9.726e-01;
+            }
+            if( w==95 )
+            {
+                r = -1.010e+00;
+            }
+            if( w==94 )
+            {
+                r = -1.048e+00;
+            }
+            if( w==93 )
+            {
+                r = -1.087e+00;
+            }
+            if( w==92 )
+            {
+                r = -1.128e+00;
+            }
+            if( w==91 )
+            {
+                r = -1.169e+00;
+            }
+            if( w==90 )
+            {
+                r = -1.211e+00;
+            }
+            if( w==89 )
+            {
+                r = -1.254e+00;
+            }
+            if( w==88 )
+            {
+                r = -1.299e+00;
+            }
+            if( w==87 )
+            {
+                r = -1.344e+00;
+            }
+            if( w==86 )
+            {
+                r = -1.390e+00;
+            }
+            if( w==85 )
+            {
+                r = -1.438e+00;
+            }
+            if( w==84 )
+            {
+                r = -1.486e+00;
+            }
+            if( w==83 )
+            {
+                r = -1.536e+00;
+            }
+            if( w==82 )
+            {
+                r = -1.587e+00;
+            }
+            if( w==81 )
+            {
+                r = -1.639e+00;
+            }
+            if( w==80 )
+            {
+                r = -1.692e+00;
+            }
+            if( w==79 )
+            {
+                r = -1.746e+00;
+            }
+            if( w==78 )
+            {
+                r = -1.802e+00;
+            }
+            if( w==77 )
+            {
+                r = -1.859e+00;
+            }
+            if( w==76 )
+            {
+                r = -1.916e+00;
+            }
+            if( w==75 )
+            {
+                r = -1.976e+00;
+            }
+            if( w==74 )
+            {
+                r = -2.036e+00;
+            }
+            if( w==73 )
+            {
+                r = -2.098e+00;
+            }
+            if( w==72 )
+            {
+                r = -2.161e+00;
+            }
+            if( w==71 )
+            {
+                r = -2.225e+00;
+            }
+            if( w==70 )
+            {
+                r = -2.290e+00;
+            }
+            if( w==69 )
+            {
+                r = -2.357e+00;
+            }
+            if( w==68 )
+            {
+                r = -2.426e+00;
+            }
+            if( w==67 )
+            {
+                r = -2.495e+00;
+            }
+            if( w==66 )
+            {
+                r = -2.566e+00;
+            }
+            if( w==65 )
+            {
+                r = -2.639e+00;
+            }
+            if( w==64 )
+            {
+                r = -2.713e+00;
+            }
+            if( w==63 )
+            {
+                r = -2.788e+00;
+            }
+            if( w==62 )
+            {
+                r = -2.865e+00;
+            }
+            if( w==61 )
+            {
+                r = -2.943e+00;
+            }
+            if( w==60 )
+            {
+                r = -3.023e+00;
+            }
+            if( w==59 )
+            {
+                r = -3.104e+00;
+            }
+            if( w==58 )
+            {
+                r = -3.187e+00;
+            }
+            if( w==57 )
+            {
+                r = -3.272e+00;
+            }
+            if( w==56 )
+            {
+                r = -3.358e+00;
+            }
+            if( w==55 )
+            {
+                r = -3.446e+00;
+            }
+            if( w==54 )
+            {
+                r = -3.536e+00;
+            }
+            if( w==53 )
+            {
+                r = -3.627e+00;
+            }
+            if( w==52 )
+            {
+                r = -3.721e+00;
+            }
+            if( w==51 )
+            {
+                r = -3.815e+00;
+            }
+            if( w==50 )
+            {
+                r = -3.912e+00;
+            }
+            if( w==49 )
+            {
+                r = -4.011e+00;
+            }
+            if( w==48 )
+            {
+                r = -4.111e+00;
+            }
+            if( w==47 )
+            {
+                r = -4.214e+00;
+            }
+            if( w==46 )
+            {
+                r = -4.318e+00;
+            }
+            if( w==45 )
+            {
+                r = -4.425e+00;
+            }
+            if( w==44 )
+            {
+                r = -4.534e+00;
+            }
+            if( w==43 )
+            {
+                r = -4.644e+00;
+            }
+            if( w==42 )
+            {
+                r = -4.757e+00;
+            }
+            if( w==41 )
+            {
+                r = -4.872e+00;
+            }
+            if( w==40 )
+            {
+                r = -4.990e+00;
+            }
+            if( w==39 )
+            {
+                r = -5.109e+00;
+            }
+            if( w==38 )
+            {
+                r = -5.232e+00;
+            }
+            if( w==37 )
+            {
+                r = -5.356e+00;
+            }
+            if( w==36 )
+            {
+                r = -5.484e+00;
+            }
+            if( w==35 )
+            {
+                r = -5.614e+00;
+            }
+            if( w==34 )
+            {
+                r = -5.746e+00;
+            }
+            if( w==33 )
+            {
+                r = -5.882e+00;
+            }
+            if( w==32 )
+            {
+                r = -6.020e+00;
+            }
+            if( w==31 )
+            {
+                r = -6.161e+00;
+            }
+            if( w==30 )
+            {
+                r = -6.305e+00;
+            }
+            if( w==29 )
+            {
+                r = -6.453e+00;
+            }
+            if( w==28 )
+            {
+                r = -6.603e+00;
+            }
+            if( w==27 )
+            {
+                r = -6.757e+00;
+            }
+            if( w==26 )
+            {
+                r = -6.915e+00;
+            }
+            if( w==25 )
+            {
+                r = -7.076e+00;
+            }
+            if( w==24 )
+            {
+                r = -7.242e+00;
+            }
+            if( w==23 )
+            {
+                r = -7.411e+00;
+            }
+            if( w==22 )
+            {
+                r = -7.584e+00;
+            }
+            if( w==21 )
+            {
+                r = -7.763e+00;
+            }
+            if( w==20 )
+            {
+                r = -7.947e+00;
+            }
+            if( w==19 )
+            {
+                r = -8.136e+00;
+            }
+            if( w==18 )
+            {
+                r = -8.330e+00;
+            }
+            if( w==17 )
+            {
+                r = -8.530e+00;
+            }
+            if( w==16 )
+            {
+                r = -8.733e+00;
+            }
+            if( w==15 )
+            {
+                r = -8.943e+00;
+            }
+            if( w==14 )
+            {
+                r = -9.162e+00;
+            }
+            if( w==13 )
+            {
+                r = -9.386e+00;
+            }
+            if( w==12 )
+            {
+                r = -9.614e+00;
+            }
+            if( w==11 )
+            {
+                r = -9.856e+00;
+            }
+            if( w==10 )
+            {
+                r = -1.010e+01;
+            }
+            if( w==9 )
+            {
+                r = -1.037e+01;
+            }
+            if( w==8 )
+            {
+                r = -1.064e+01;
+            }
+            if( w==7 )
+            {
+                r = -1.092e+01;
+            }
+            if( w==6 )
+            {
+                r = -1.122e+01;
+            }
+            if( w==5 )
+            {
+                r = -1.156e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.192e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.225e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.276e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.317e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.386e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 21)
+        *************************************************************************/
+        private static double w21(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(2.877064e+01*s)+1.155000e+02);
+            if( w>=115 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==114 )
+            {
+                r = -7.207e-01;
+            }
+            if( w==113 )
+            {
+                r = -7.489e-01;
+            }
+            if( w==112 )
+            {
+                r = -7.779e-01;
+            }
+            if( w==111 )
+            {
+                r = -8.077e-01;
+            }
+            if( w==110 )
+            {
+                r = -8.383e-01;
+            }
+            if( w==109 )
+            {
+                r = -8.697e-01;
+            }
+            if( w==108 )
+            {
+                r = -9.018e-01;
+            }
+            if( w==107 )
+            {
+                r = -9.348e-01;
+            }
+            if( w==106 )
+            {
+                r = -9.685e-01;
+            }
+            if( w==105 )
+            {
+                r = -1.003e+00;
+            }
+            if( w==104 )
+            {
+                r = -1.039e+00;
+            }
+            if( w==103 )
+            {
+                r = -1.075e+00;
+            }
+            if( w==102 )
+            {
+                r = -1.112e+00;
+            }
+            if( w==101 )
+            {
+                r = -1.150e+00;
+            }
+            if( w==100 )
+            {
+                r = -1.189e+00;
+            }
+            if( w==99 )
+            {
+                r = -1.229e+00;
+            }
+            if( w==98 )
+            {
+                r = -1.269e+00;
+            }
+            if( w==97 )
+            {
+                r = -1.311e+00;
+            }
+            if( w==96 )
+            {
+                r = -1.353e+00;
+            }
+            if( w==95 )
+            {
+                r = -1.397e+00;
+            }
+            if( w==94 )
+            {
+                r = -1.441e+00;
+            }
+            if( w==93 )
+            {
+                r = -1.486e+00;
+            }
+            if( w==92 )
+            {
+                r = -1.533e+00;
+            }
+            if( w==91 )
+            {
+                r = -1.580e+00;
+            }
+            if( w==90 )
+            {
+                r = -1.628e+00;
+            }
+            if( w==89 )
+            {
+                r = -1.677e+00;
+            }
+            if( w==88 )
+            {
+                r = -1.728e+00;
+            }
+            if( w==87 )
+            {
+                r = -1.779e+00;
+            }
+            if( w==86 )
+            {
+                r = -1.831e+00;
+            }
+            if( w==85 )
+            {
+                r = -1.884e+00;
+            }
+            if( w==84 )
+            {
+                r = -1.939e+00;
+            }
+            if( w==83 )
+            {
+                r = -1.994e+00;
+            }
+            if( w==82 )
+            {
+                r = -2.051e+00;
+            }
+            if( w==81 )
+            {
+                r = -2.108e+00;
+            }
+            if( w==80 )
+            {
+                r = -2.167e+00;
+            }
+            if( w==79 )
+            {
+                r = -2.227e+00;
+            }
+            if( w==78 )
+            {
+                r = -2.288e+00;
+            }
+            if( w==77 )
+            {
+                r = -2.350e+00;
+            }
+            if( w==76 )
+            {
+                r = -2.414e+00;
+            }
+            if( w==75 )
+            {
+                r = -2.478e+00;
+            }
+            if( w==74 )
+            {
+                r = -2.544e+00;
+            }
+            if( w==73 )
+            {
+                r = -2.611e+00;
+            }
+            if( w==72 )
+            {
+                r = -2.679e+00;
+            }
+            if( w==71 )
+            {
+                r = -2.748e+00;
+            }
+            if( w==70 )
+            {
+                r = -2.819e+00;
+            }
+            if( w==69 )
+            {
+                r = -2.891e+00;
+            }
+            if( w==68 )
+            {
+                r = -2.964e+00;
+            }
+            if( w==67 )
+            {
+                r = -3.039e+00;
+            }
+            if( w==66 )
+            {
+                r = -3.115e+00;
+            }
+            if( w==65 )
+            {
+                r = -3.192e+00;
+            }
+            if( w==64 )
+            {
+                r = -3.270e+00;
+            }
+            if( w==63 )
+            {
+                r = -3.350e+00;
+            }
+            if( w==62 )
+            {
+                r = -3.432e+00;
+            }
+            if( w==61 )
+            {
+                r = -3.515e+00;
+            }
+            if( w==60 )
+            {
+                r = -3.599e+00;
+            }
+            if( w==59 )
+            {
+                r = -3.685e+00;
+            }
+            if( w==58 )
+            {
+                r = -3.772e+00;
+            }
+            if( w==57 )
+            {
+                r = -3.861e+00;
+            }
+            if( w==56 )
+            {
+                r = -3.952e+00;
+            }
+            if( w==55 )
+            {
+                r = -4.044e+00;
+            }
+            if( w==54 )
+            {
+                r = -4.138e+00;
+            }
+            if( w==53 )
+            {
+                r = -4.233e+00;
+            }
+            if( w==52 )
+            {
+                r = -4.330e+00;
+            }
+            if( w==51 )
+            {
+                r = -4.429e+00;
+            }
+            if( w==50 )
+            {
+                r = -4.530e+00;
+            }
+            if( w==49 )
+            {
+                r = -4.632e+00;
+            }
+            if( w==48 )
+            {
+                r = -4.736e+00;
+            }
+            if( w==47 )
+            {
+                r = -4.842e+00;
+            }
+            if( w==46 )
+            {
+                r = -4.950e+00;
+            }
+            if( w==45 )
+            {
+                r = -5.060e+00;
+            }
+            if( w==44 )
+            {
+                r = -5.172e+00;
+            }
+            if( w==43 )
+            {
+                r = -5.286e+00;
+            }
+            if( w==42 )
+            {
+                r = -5.402e+00;
+            }
+            if( w==41 )
+            {
+                r = -5.520e+00;
+            }
+            if( w==40 )
+            {
+                r = -5.641e+00;
+            }
+            if( w==39 )
+            {
+                r = -5.763e+00;
+            }
+            if( w==38 )
+            {
+                r = -5.889e+00;
+            }
+            if( w==37 )
+            {
+                r = -6.016e+00;
+            }
+            if( w==36 )
+            {
+                r = -6.146e+00;
+            }
+            if( w==35 )
+            {
+                r = -6.278e+00;
+            }
+            if( w==34 )
+            {
+                r = -6.413e+00;
+            }
+            if( w==33 )
+            {
+                r = -6.551e+00;
+            }
+            if( w==32 )
+            {
+                r = -6.692e+00;
+            }
+            if( w==31 )
+            {
+                r = -6.835e+00;
+            }
+            if( w==30 )
+            {
+                r = -6.981e+00;
+            }
+            if( w==29 )
+            {
+                r = -7.131e+00;
+            }
+            if( w==28 )
+            {
+                r = -7.283e+00;
+            }
+            if( w==27 )
+            {
+                r = -7.439e+00;
+            }
+            if( w==26 )
+            {
+                r = -7.599e+00;
+            }
+            if( w==25 )
+            {
+                r = -7.762e+00;
+            }
+            if( w==24 )
+            {
+                r = -7.928e+00;
+            }
+            if( w==23 )
+            {
+                r = -8.099e+00;
+            }
+            if( w==22 )
+            {
+                r = -8.274e+00;
+            }
+            if( w==21 )
+            {
+                r = -8.454e+00;
+            }
+            if( w==20 )
+            {
+                r = -8.640e+00;
+            }
+            if( w==19 )
+            {
+                r = -8.829e+00;
+            }
+            if( w==18 )
+            {
+                r = -9.023e+00;
+            }
+            if( w==17 )
+            {
+                r = -9.223e+00;
+            }
+            if( w==16 )
+            {
+                r = -9.426e+00;
+            }
+            if( w==15 )
+            {
+                r = -9.636e+00;
+            }
+            if( w==14 )
+            {
+                r = -9.856e+00;
+            }
+            if( w==13 )
+            {
+                r = -1.008e+01;
+            }
+            if( w==12 )
+            {
+                r = -1.031e+01;
+            }
+            if( w==11 )
+            {
+                r = -1.055e+01;
+            }
+            if( w==10 )
+            {
+                r = -1.079e+01;
+            }
+            if( w==9 )
+            {
+                r = -1.106e+01;
+            }
+            if( w==8 )
+            {
+                r = -1.134e+01;
+            }
+            if( w==7 )
+            {
+                r = -1.161e+01;
+            }
+            if( w==6 )
+            {
+                r = -1.192e+01;
+            }
+            if( w==5 )
+            {
+                r = -1.225e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.261e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.295e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.346e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.386e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.456e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 22)
+        *************************************************************************/
+        private static double w22(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(3.080179e+01*s)+1.265000e+02);
+            if( w>=126 )
+            {
+                r = -6.931e-01;
+            }
+            if( w==125 )
+            {
+                r = -7.189e-01;
+            }
+            if( w==124 )
+            {
+                r = -7.452e-01;
+            }
+            if( w==123 )
+            {
+                r = -7.722e-01;
+            }
+            if( w==122 )
+            {
+                r = -7.999e-01;
+            }
+            if( w==121 )
+            {
+                r = -8.283e-01;
+            }
+            if( w==120 )
+            {
+                r = -8.573e-01;
+            }
+            if( w==119 )
+            {
+                r = -8.871e-01;
+            }
+            if( w==118 )
+            {
+                r = -9.175e-01;
+            }
+            if( w==117 )
+            {
+                r = -9.486e-01;
+            }
+            if( w==116 )
+            {
+                r = -9.805e-01;
+            }
+            if( w==115 )
+            {
+                r = -1.013e+00;
+            }
+            if( w==114 )
+            {
+                r = -1.046e+00;
+            }
+            if( w==113 )
+            {
+                r = -1.080e+00;
+            }
+            if( w==112 )
+            {
+                r = -1.115e+00;
+            }
+            if( w==111 )
+            {
+                r = -1.151e+00;
+            }
+            if( w==110 )
+            {
+                r = -1.187e+00;
+            }
+            if( w==109 )
+            {
+                r = -1.224e+00;
+            }
+            if( w==108 )
+            {
+                r = -1.262e+00;
+            }
+            if( w==107 )
+            {
+                r = -1.301e+00;
+            }
+            if( w==106 )
+            {
+                r = -1.340e+00;
+            }
+            if( w==105 )
+            {
+                r = -1.381e+00;
+            }
+            if( w==104 )
+            {
+                r = -1.422e+00;
+            }
+            if( w==103 )
+            {
+                r = -1.464e+00;
+            }
+            if( w==102 )
+            {
+                r = -1.506e+00;
+            }
+            if( w==101 )
+            {
+                r = -1.550e+00;
+            }
+            if( w==100 )
+            {
+                r = -1.594e+00;
+            }
+            if( w==99 )
+            {
+                r = -1.640e+00;
+            }
+            if( w==98 )
+            {
+                r = -1.686e+00;
+            }
+            if( w==97 )
+            {
+                r = -1.733e+00;
+            }
+            if( w==96 )
+            {
+                r = -1.781e+00;
+            }
+            if( w==95 )
+            {
+                r = -1.830e+00;
+            }
+            if( w==94 )
+            {
+                r = -1.880e+00;
+            }
+            if( w==93 )
+            {
+                r = -1.930e+00;
+            }
+            if( w==92 )
+            {
+                r = -1.982e+00;
+            }
+            if( w==91 )
+            {
+                r = -2.034e+00;
+            }
+            if( w==90 )
+            {
+                r = -2.088e+00;
+            }
+            if( w==89 )
+            {
+                r = -2.142e+00;
+            }
+            if( w==88 )
+            {
+                r = -2.198e+00;
+            }
+            if( w==87 )
+            {
+                r = -2.254e+00;
+            }
+            if( w==86 )
+            {
+                r = -2.312e+00;
+            }
+            if( w==85 )
+            {
+                r = -2.370e+00;
+            }
+            if( w==84 )
+            {
+                r = -2.429e+00;
+            }
+            if( w==83 )
+            {
+                r = -2.490e+00;
+            }
+            if( w==82 )
+            {
+                r = -2.551e+00;
+            }
+            if( w==81 )
+            {
+                r = -2.614e+00;
+            }
+            if( w==80 )
+            {
+                r = -2.677e+00;
+            }
+            if( w==79 )
+            {
+                r = -2.742e+00;
+            }
+            if( w==78 )
+            {
+                r = -2.808e+00;
+            }
+            if( w==77 )
+            {
+                r = -2.875e+00;
+            }
+            if( w==76 )
+            {
+                r = -2.943e+00;
+            }
+            if( w==75 )
+            {
+                r = -3.012e+00;
+            }
+            if( w==74 )
+            {
+                r = -3.082e+00;
+            }
+            if( w==73 )
+            {
+                r = -3.153e+00;
+            }
+            if( w==72 )
+            {
+                r = -3.226e+00;
+            }
+            if( w==71 )
+            {
+                r = -3.300e+00;
+            }
+            if( w==70 )
+            {
+                r = -3.375e+00;
+            }
+            if( w==69 )
+            {
+                r = -3.451e+00;
+            }
+            if( w==68 )
+            {
+                r = -3.529e+00;
+            }
+            if( w==67 )
+            {
+                r = -3.607e+00;
+            }
+            if( w==66 )
+            {
+                r = -3.687e+00;
+            }
+            if( w==65 )
+            {
+                r = -3.769e+00;
+            }
+            if( w==64 )
+            {
+                r = -3.851e+00;
+            }
+            if( w==63 )
+            {
+                r = -3.935e+00;
+            }
+            if( w==62 )
+            {
+                r = -4.021e+00;
+            }
+            if( w==61 )
+            {
+                r = -4.108e+00;
+            }
+            if( w==60 )
+            {
+                r = -4.196e+00;
+            }
+            if( w==59 )
+            {
+                r = -4.285e+00;
+            }
+            if( w==58 )
+            {
+                r = -4.376e+00;
+            }
+            if( w==57 )
+            {
+                r = -4.469e+00;
+            }
+            if( w==56 )
+            {
+                r = -4.563e+00;
+            }
+            if( w==55 )
+            {
+                r = -4.659e+00;
+            }
+            if( w==54 )
+            {
+                r = -4.756e+00;
+            }
+            if( w==53 )
+            {
+                r = -4.855e+00;
+            }
+            if( w==52 )
+            {
+                r = -4.955e+00;
+            }
+            if( w==51 )
+            {
+                r = -5.057e+00;
+            }
+            if( w==50 )
+            {
+                r = -5.161e+00;
+            }
+            if( w==49 )
+            {
+                r = -5.266e+00;
+            }
+            if( w==48 )
+            {
+                r = -5.374e+00;
+            }
+            if( w==47 )
+            {
+                r = -5.483e+00;
+            }
+            if( w==46 )
+            {
+                r = -5.594e+00;
+            }
+            if( w==45 )
+            {
+                r = -5.706e+00;
+            }
+            if( w==44 )
+            {
+                r = -5.821e+00;
+            }
+            if( w==43 )
+            {
+                r = -5.938e+00;
+            }
+            if( w==42 )
+            {
+                r = -6.057e+00;
+            }
+            if( w==41 )
+            {
+                r = -6.177e+00;
+            }
+            if( w==40 )
+            {
+                r = -6.300e+00;
+            }
+            if( w==39 )
+            {
+                r = -6.426e+00;
+            }
+            if( w==38 )
+            {
+                r = -6.553e+00;
+            }
+            if( w==37 )
+            {
+                r = -6.683e+00;
+            }
+            if( w==36 )
+            {
+                r = -6.815e+00;
+            }
+            if( w==35 )
+            {
+                r = -6.949e+00;
+            }
+            if( w==34 )
+            {
+                r = -7.086e+00;
+            }
+            if( w==33 )
+            {
+                r = -7.226e+00;
+            }
+            if( w==32 )
+            {
+                r = -7.368e+00;
+            }
+            if( w==31 )
+            {
+                r = -7.513e+00;
+            }
+            if( w==30 )
+            {
+                r = -7.661e+00;
+            }
+            if( w==29 )
+            {
+                r = -7.813e+00;
+            }
+            if( w==28 )
+            {
+                r = -7.966e+00;
+            }
+            if( w==27 )
+            {
+                r = -8.124e+00;
+            }
+            if( w==26 )
+            {
+                r = -8.285e+00;
+            }
+            if( w==25 )
+            {
+                r = -8.449e+00;
+            }
+            if( w==24 )
+            {
+                r = -8.617e+00;
+            }
+            if( w==23 )
+            {
+                r = -8.789e+00;
+            }
+            if( w==22 )
+            {
+                r = -8.965e+00;
+            }
+            if( w==21 )
+            {
+                r = -9.147e+00;
+            }
+            if( w==20 )
+            {
+                r = -9.333e+00;
+            }
+            if( w==19 )
+            {
+                r = -9.522e+00;
+            }
+            if( w==18 )
+            {
+                r = -9.716e+00;
+            }
+            if( w==17 )
+            {
+                r = -9.917e+00;
+            }
+            if( w==16 )
+            {
+                r = -1.012e+01;
+            }
+            if( w==15 )
+            {
+                r = -1.033e+01;
+            }
+            if( w==14 )
+            {
+                r = -1.055e+01;
+            }
+            if( w==13 )
+            {
+                r = -1.077e+01;
+            }
+            if( w==12 )
+            {
+                r = -1.100e+01;
+            }
+            if( w==11 )
+            {
+                r = -1.124e+01;
+            }
+            if( w==10 )
+            {
+                r = -1.149e+01;
+            }
+            if( w==9 )
+            {
+                r = -1.175e+01;
+            }
+            if( w==8 )
+            {
+                r = -1.203e+01;
+            }
+            if( w==7 )
+            {
+                r = -1.230e+01;
+            }
+            if( w==6 )
+            {
+                r = -1.261e+01;
+            }
+            if( w==5 )
+            {
+                r = -1.295e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.330e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.364e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.415e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.456e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.525e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 23)
+        *************************************************************************/
+        private static double w23(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(3.287856e+01*s)+1.380000e+02);
+            if( w>=138 )
+            {
+                r = -6.813e-01;
+            }
+            if( w==137 )
+            {
+                r = -7.051e-01;
+            }
+            if( w==136 )
+            {
+                r = -7.295e-01;
+            }
+            if( w==135 )
+            {
+                r = -7.544e-01;
+            }
+            if( w==134 )
+            {
+                r = -7.800e-01;
+            }
+            if( w==133 )
+            {
+                r = -8.061e-01;
+            }
+            if( w==132 )
+            {
+                r = -8.328e-01;
+            }
+            if( w==131 )
+            {
+                r = -8.601e-01;
+            }
+            if( w==130 )
+            {
+                r = -8.880e-01;
+            }
+            if( w==129 )
+            {
+                r = -9.166e-01;
+            }
+            if( w==128 )
+            {
+                r = -9.457e-01;
+            }
+            if( w==127 )
+            {
+                r = -9.755e-01;
+            }
+            if( w==126 )
+            {
+                r = -1.006e+00;
+            }
+            if( w==125 )
+            {
+                r = -1.037e+00;
+            }
+            if( w==124 )
+            {
+                r = -1.069e+00;
+            }
+            if( w==123 )
+            {
+                r = -1.101e+00;
+            }
+            if( w==122 )
+            {
+                r = -1.134e+00;
+            }
+            if( w==121 )
+            {
+                r = -1.168e+00;
+            }
+            if( w==120 )
+            {
+                r = -1.202e+00;
+            }
+            if( w==119 )
+            {
+                r = -1.237e+00;
+            }
+            if( w==118 )
+            {
+                r = -1.273e+00;
+            }
+            if( w==117 )
+            {
+                r = -1.309e+00;
+            }
+            if( w==116 )
+            {
+                r = -1.347e+00;
+            }
+            if( w==115 )
+            {
+                r = -1.384e+00;
+            }
+            if( w==114 )
+            {
+                r = -1.423e+00;
+            }
+            if( w==113 )
+            {
+                r = -1.462e+00;
+            }
+            if( w==112 )
+            {
+                r = -1.502e+00;
+            }
+            if( w==111 )
+            {
+                r = -1.543e+00;
+            }
+            if( w==110 )
+            {
+                r = -1.585e+00;
+            }
+            if( w==109 )
+            {
+                r = -1.627e+00;
+            }
+            if( w==108 )
+            {
+                r = -1.670e+00;
+            }
+            if( w==107 )
+            {
+                r = -1.714e+00;
+            }
+            if( w==106 )
+            {
+                r = -1.758e+00;
+            }
+            if( w==105 )
+            {
+                r = -1.804e+00;
+            }
+            if( w==104 )
+            {
+                r = -1.850e+00;
+            }
+            if( w==103 )
+            {
+                r = -1.897e+00;
+            }
+            if( w==102 )
+            {
+                r = -1.944e+00;
+            }
+            if( w==101 )
+            {
+                r = -1.993e+00;
+            }
+            if( w==100 )
+            {
+                r = -2.042e+00;
+            }
+            if( w==99 )
+            {
+                r = -2.093e+00;
+            }
+            if( w==98 )
+            {
+                r = -2.144e+00;
+            }
+            if( w==97 )
+            {
+                r = -2.195e+00;
+            }
+            if( w==96 )
+            {
+                r = -2.248e+00;
+            }
+            if( w==95 )
+            {
+                r = -2.302e+00;
+            }
+            if( w==94 )
+            {
+                r = -2.356e+00;
+            }
+            if( w==93 )
+            {
+                r = -2.412e+00;
+            }
+            if( w==92 )
+            {
+                r = -2.468e+00;
+            }
+            if( w==91 )
+            {
+                r = -2.525e+00;
+            }
+            if( w==90 )
+            {
+                r = -2.583e+00;
+            }
+            if( w==89 )
+            {
+                r = -2.642e+00;
+            }
+            if( w==88 )
+            {
+                r = -2.702e+00;
+            }
+            if( w==87 )
+            {
+                r = -2.763e+00;
+            }
+            if( w==86 )
+            {
+                r = -2.825e+00;
+            }
+            if( w==85 )
+            {
+                r = -2.888e+00;
+            }
+            if( w==84 )
+            {
+                r = -2.951e+00;
+            }
+            if( w==83 )
+            {
+                r = -3.016e+00;
+            }
+            if( w==82 )
+            {
+                r = -3.082e+00;
+            }
+            if( w==81 )
+            {
+                r = -3.149e+00;
+            }
+            if( w==80 )
+            {
+                r = -3.216e+00;
+            }
+            if( w==79 )
+            {
+                r = -3.285e+00;
+            }
+            if( w==78 )
+            {
+                r = -3.355e+00;
+            }
+            if( w==77 )
+            {
+                r = -3.426e+00;
+            }
+            if( w==76 )
+            {
+                r = -3.498e+00;
+            }
+            if( w==75 )
+            {
+                r = -3.571e+00;
+            }
+            if( w==74 )
+            {
+                r = -3.645e+00;
+            }
+            if( w==73 )
+            {
+                r = -3.721e+00;
+            }
+            if( w==72 )
+            {
+                r = -3.797e+00;
+            }
+            if( w==71 )
+            {
+                r = -3.875e+00;
+            }
+            if( w==70 )
+            {
+                r = -3.953e+00;
+            }
+            if( w==69 )
+            {
+                r = -4.033e+00;
+            }
+            if( w==68 )
+            {
+                r = -4.114e+00;
+            }
+            if( w==67 )
+            {
+                r = -4.197e+00;
+            }
+            if( w==66 )
+            {
+                r = -4.280e+00;
+            }
+            if( w==65 )
+            {
+                r = -4.365e+00;
+            }
+            if( w==64 )
+            {
+                r = -4.451e+00;
+            }
+            if( w==63 )
+            {
+                r = -4.539e+00;
+            }
+            if( w==62 )
+            {
+                r = -4.628e+00;
+            }
+            if( w==61 )
+            {
+                r = -4.718e+00;
+            }
+            if( w==60 )
+            {
+                r = -4.809e+00;
+            }
+            if( w==59 )
+            {
+                r = -4.902e+00;
+            }
+            if( w==58 )
+            {
+                r = -4.996e+00;
+            }
+            if( w==57 )
+            {
+                r = -5.092e+00;
+            }
+            if( w==56 )
+            {
+                r = -5.189e+00;
+            }
+            if( w==55 )
+            {
+                r = -5.287e+00;
+            }
+            if( w==54 )
+            {
+                r = -5.388e+00;
+            }
+            if( w==53 )
+            {
+                r = -5.489e+00;
+            }
+            if( w==52 )
+            {
+                r = -5.592e+00;
+            }
+            if( w==51 )
+            {
+                r = -5.697e+00;
+            }
+            if( w==50 )
+            {
+                r = -5.804e+00;
+            }
+            if( w==49 )
+            {
+                r = -5.912e+00;
+            }
+            if( w==48 )
+            {
+                r = -6.022e+00;
+            }
+            if( w==47 )
+            {
+                r = -6.133e+00;
+            }
+            if( w==46 )
+            {
+                r = -6.247e+00;
+            }
+            if( w==45 )
+            {
+                r = -6.362e+00;
+            }
+            if( w==44 )
+            {
+                r = -6.479e+00;
+            }
+            if( w==43 )
+            {
+                r = -6.598e+00;
+            }
+            if( w==42 )
+            {
+                r = -6.719e+00;
+            }
+            if( w==41 )
+            {
+                r = -6.842e+00;
+            }
+            if( w==40 )
+            {
+                r = -6.967e+00;
+            }
+            if( w==39 )
+            {
+                r = -7.094e+00;
+            }
+            if( w==38 )
+            {
+                r = -7.224e+00;
+            }
+            if( w==37 )
+            {
+                r = -7.355e+00;
+            }
+            if( w==36 )
+            {
+                r = -7.489e+00;
+            }
+            if( w==35 )
+            {
+                r = -7.625e+00;
+            }
+            if( w==34 )
+            {
+                r = -7.764e+00;
+            }
+            if( w==33 )
+            {
+                r = -7.905e+00;
+            }
+            if( w==32 )
+            {
+                r = -8.049e+00;
+            }
+            if( w==31 )
+            {
+                r = -8.196e+00;
+            }
+            if( w==30 )
+            {
+                r = -8.345e+00;
+            }
+            if( w==29 )
+            {
+                r = -8.498e+00;
+            }
+            if( w==28 )
+            {
+                r = -8.653e+00;
+            }
+            if( w==27 )
+            {
+                r = -8.811e+00;
+            }
+            if( w==26 )
+            {
+                r = -8.974e+00;
+            }
+            if( w==25 )
+            {
+                r = -9.139e+00;
+            }
+            if( w==24 )
+            {
+                r = -9.308e+00;
+            }
+            if( w==23 )
+            {
+                r = -9.481e+00;
+            }
+            if( w==22 )
+            {
+                r = -9.658e+00;
+            }
+            if( w==21 )
+            {
+                r = -9.840e+00;
+            }
+            if( w==20 )
+            {
+                r = -1.003e+01;
+            }
+            if( w==19 )
+            {
+                r = -1.022e+01;
+            }
+            if( w==18 )
+            {
+                r = -1.041e+01;
+            }
+            if( w==17 )
+            {
+                r = -1.061e+01;
+            }
+            if( w==16 )
+            {
+                r = -1.081e+01;
+            }
+            if( w==15 )
+            {
+                r = -1.102e+01;
+            }
+            if( w==14 )
+            {
+                r = -1.124e+01;
+            }
+            if( w==13 )
+            {
+                r = -1.147e+01;
+            }
+            if( w==12 )
+            {
+                r = -1.169e+01;
+            }
+            if( w==11 )
+            {
+                r = -1.194e+01;
+            }
+            if( w==10 )
+            {
+                r = -1.218e+01;
+            }
+            if( w==9 )
+            {
+                r = -1.245e+01;
+            }
+            if( w==8 )
+            {
+                r = -1.272e+01;
+            }
+            if( w==7 )
+            {
+                r = -1.300e+01;
+            }
+            if( w==6 )
+            {
+                r = -1.330e+01;
+            }
+            if( w==5 )
+            {
+                r = -1.364e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.400e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.433e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.484e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.525e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.594e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 24)
+        *************************************************************************/
+        private static double w24(double s)
+        {
+            double result = 0;
+            int w = 0;
+            double r = 0;
+
+            w = (int)Math.Round(-(3.500000e+01*s)+1.500000e+02);
+            if( w>=150 )
+            {
+                r = -6.820e-01;
+            }
+            if( w==149 )
+            {
+                r = -7.044e-01;
+            }
+            if( w==148 )
+            {
+                r = -7.273e-01;
+            }
+            if( w==147 )
+            {
+                r = -7.507e-01;
+            }
+            if( w==146 )
+            {
+                r = -7.746e-01;
+            }
+            if( w==145 )
+            {
+                r = -7.990e-01;
+            }
+            if( w==144 )
+            {
+                r = -8.239e-01;
+            }
+            if( w==143 )
+            {
+                r = -8.494e-01;
+            }
+            if( w==142 )
+            {
+                r = -8.754e-01;
+            }
+            if( w==141 )
+            {
+                r = -9.020e-01;
+            }
+            if( w==140 )
+            {
+                r = -9.291e-01;
+            }
+            if( w==139 )
+            {
+                r = -9.567e-01;
+            }
+            if( w==138 )
+            {
+                r = -9.849e-01;
+            }
+            if( w==137 )
+            {
+                r = -1.014e+00;
+            }
+            if( w==136 )
+            {
+                r = -1.043e+00;
+            }
+            if( w==135 )
+            {
+                r = -1.073e+00;
+            }
+            if( w==134 )
+            {
+                r = -1.103e+00;
+            }
+            if( w==133 )
+            {
+                r = -1.135e+00;
+            }
+            if( w==132 )
+            {
+                r = -1.166e+00;
+            }
+            if( w==131 )
+            {
+                r = -1.198e+00;
+            }
+            if( w==130 )
+            {
+                r = -1.231e+00;
+            }
+            if( w==129 )
+            {
+                r = -1.265e+00;
+            }
+            if( w==128 )
+            {
+                r = -1.299e+00;
+            }
+            if( w==127 )
+            {
+                r = -1.334e+00;
+            }
+            if( w==126 )
+            {
+                r = -1.369e+00;
+            }
+            if( w==125 )
+            {
+                r = -1.405e+00;
+            }
+            if( w==124 )
+            {
+                r = -1.441e+00;
+            }
+            if( w==123 )
+            {
+                r = -1.479e+00;
+            }
+            if( w==122 )
+            {
+                r = -1.517e+00;
+            }
+            if( w==121 )
+            {
+                r = -1.555e+00;
+            }
+            if( w==120 )
+            {
+                r = -1.594e+00;
+            }
+            if( w==119 )
+            {
+                r = -1.634e+00;
+            }
+            if( w==118 )
+            {
+                r = -1.675e+00;
+            }
+            if( w==117 )
+            {
+                r = -1.716e+00;
+            }
+            if( w==116 )
+            {
+                r = -1.758e+00;
+            }
+            if( w==115 )
+            {
+                r = -1.800e+00;
+            }
+            if( w==114 )
+            {
+                r = -1.844e+00;
+            }
+            if( w==113 )
+            {
+                r = -1.888e+00;
+            }
+            if( w==112 )
+            {
+                r = -1.932e+00;
+            }
+            if( w==111 )
+            {
+                r = -1.978e+00;
+            }
+            if( w==110 )
+            {
+                r = -2.024e+00;
+            }
+            if( w==109 )
+            {
+                r = -2.070e+00;
+            }
+            if( w==108 )
+            {
+                r = -2.118e+00;
+            }
+            if( w==107 )
+            {
+                r = -2.166e+00;
+            }
+            if( w==106 )
+            {
+                r = -2.215e+00;
+            }
+            if( w==105 )
+            {
+                r = -2.265e+00;
+            }
+            if( w==104 )
+            {
+                r = -2.316e+00;
+            }
+            if( w==103 )
+            {
+                r = -2.367e+00;
+            }
+            if( w==102 )
+            {
+                r = -2.419e+00;
+            }
+            if( w==101 )
+            {
+                r = -2.472e+00;
+            }
+            if( w==100 )
+            {
+                r = -2.526e+00;
+            }
+            if( w==99 )
+            {
+                r = -2.580e+00;
+            }
+            if( w==98 )
+            {
+                r = -2.636e+00;
+            }
+            if( w==97 )
+            {
+                r = -2.692e+00;
+            }
+            if( w==96 )
+            {
+                r = -2.749e+00;
+            }
+            if( w==95 )
+            {
+                r = -2.806e+00;
+            }
+            if( w==94 )
+            {
+                r = -2.865e+00;
+            }
+            if( w==93 )
+            {
+                r = -2.925e+00;
+            }
+            if( w==92 )
+            {
+                r = -2.985e+00;
+            }
+            if( w==91 )
+            {
+                r = -3.046e+00;
+            }
+            if( w==90 )
+            {
+                r = -3.108e+00;
+            }
+            if( w==89 )
+            {
+                r = -3.171e+00;
+            }
+            if( w==88 )
+            {
+                r = -3.235e+00;
+            }
+            if( w==87 )
+            {
+                r = -3.300e+00;
+            }
+            if( w==86 )
+            {
+                r = -3.365e+00;
+            }
+            if( w==85 )
+            {
+                r = -3.432e+00;
+            }
+            if( w==84 )
+            {
+                r = -3.499e+00;
+            }
+            if( w==83 )
+            {
+                r = -3.568e+00;
+            }
+            if( w==82 )
+            {
+                r = -3.637e+00;
+            }
+            if( w==81 )
+            {
+                r = -3.708e+00;
+            }
+            if( w==80 )
+            {
+                r = -3.779e+00;
+            }
+            if( w==79 )
+            {
+                r = -3.852e+00;
+            }
+            if( w==78 )
+            {
+                r = -3.925e+00;
+            }
+            if( w==77 )
+            {
+                r = -4.000e+00;
+            }
+            if( w==76 )
+            {
+                r = -4.075e+00;
+            }
+            if( w==75 )
+            {
+                r = -4.151e+00;
+            }
+            if( w==74 )
+            {
+                r = -4.229e+00;
+            }
+            if( w==73 )
+            {
+                r = -4.308e+00;
+            }
+            if( w==72 )
+            {
+                r = -4.387e+00;
+            }
+            if( w==71 )
+            {
+                r = -4.468e+00;
+            }
+            if( w==70 )
+            {
+                r = -4.550e+00;
+            }
+            if( w==69 )
+            {
+                r = -4.633e+00;
+            }
+            if( w==68 )
+            {
+                r = -4.718e+00;
+            }
+            if( w==67 )
+            {
+                r = -4.803e+00;
+            }
+            if( w==66 )
+            {
+                r = -4.890e+00;
+            }
+            if( w==65 )
+            {
+                r = -4.978e+00;
+            }
+            if( w==64 )
+            {
+                r = -5.067e+00;
+            }
+            if( w==63 )
+            {
+                r = -5.157e+00;
+            }
+            if( w==62 )
+            {
+                r = -5.249e+00;
+            }
+            if( w==61 )
+            {
+                r = -5.342e+00;
+            }
+            if( w==60 )
+            {
+                r = -5.436e+00;
+            }
+            if( w==59 )
+            {
+                r = -5.531e+00;
+            }
+            if( w==58 )
+            {
+                r = -5.628e+00;
+            }
+            if( w==57 )
+            {
+                r = -5.727e+00;
+            }
+            if( w==56 )
+            {
+                r = -5.826e+00;
+            }
+            if( w==55 )
+            {
+                r = -5.927e+00;
+            }
+            if( w==54 )
+            {
+                r = -6.030e+00;
+            }
+            if( w==53 )
+            {
+                r = -6.134e+00;
+            }
+            if( w==52 )
+            {
+                r = -6.240e+00;
+            }
+            if( w==51 )
+            {
+                r = -6.347e+00;
+            }
+            if( w==50 )
+            {
+                r = -6.456e+00;
+            }
+            if( w==49 )
+            {
+                r = -6.566e+00;
+            }
+            if( w==48 )
+            {
+                r = -6.678e+00;
+            }
+            if( w==47 )
+            {
+                r = -6.792e+00;
+            }
+            if( w==46 )
+            {
+                r = -6.907e+00;
+            }
+            if( w==45 )
+            {
+                r = -7.025e+00;
+            }
+            if( w==44 )
+            {
+                r = -7.144e+00;
+            }
+            if( w==43 )
+            {
+                r = -7.265e+00;
+            }
+            if( w==42 )
+            {
+                r = -7.387e+00;
+            }
+            if( w==41 )
+            {
+                r = -7.512e+00;
+            }
+            if( w==40 )
+            {
+                r = -7.639e+00;
+            }
+            if( w==39 )
+            {
+                r = -7.768e+00;
+            }
+            if( w==38 )
+            {
+                r = -7.899e+00;
+            }
+            if( w==37 )
+            {
+                r = -8.032e+00;
+            }
+            if( w==36 )
+            {
+                r = -8.167e+00;
+            }
+            if( w==35 )
+            {
+                r = -8.305e+00;
+            }
+            if( w==34 )
+            {
+                r = -8.445e+00;
+            }
+            if( w==33 )
+            {
+                r = -8.588e+00;
+            }
+            if( w==32 )
+            {
+                r = -8.733e+00;
+            }
+            if( w==31 )
+            {
+                r = -8.881e+00;
+            }
+            if( w==30 )
+            {
+                r = -9.031e+00;
+            }
+            if( w==29 )
+            {
+                r = -9.185e+00;
+            }
+            if( w==28 )
+            {
+                r = -9.341e+00;
+            }
+            if( w==27 )
+            {
+                r = -9.501e+00;
+            }
+            if( w==26 )
+            {
+                r = -9.664e+00;
+            }
+            if( w==25 )
+            {
+                r = -9.830e+00;
+            }
+            if( w==24 )
+            {
+                r = -1.000e+01;
+            }
+            if( w==23 )
+            {
+                r = -1.017e+01;
+            }
+            if( w==22 )
+            {
+                r = -1.035e+01;
+            }
+            if( w==21 )
+            {
+                r = -1.053e+01;
+            }
+            if( w==20 )
+            {
+                r = -1.072e+01;
+            }
+            if( w==19 )
+            {
+                r = -1.091e+01;
+            }
+            if( w==18 )
+            {
+                r = -1.110e+01;
+            }
+            if( w==17 )
+            {
+                r = -1.130e+01;
+            }
+            if( w==16 )
+            {
+                r = -1.151e+01;
+            }
+            if( w==15 )
+            {
+                r = -1.172e+01;
+            }
+            if( w==14 )
+            {
+                r = -1.194e+01;
+            }
+            if( w==13 )
+            {
+                r = -1.216e+01;
+            }
+            if( w==12 )
+            {
+                r = -1.239e+01;
+            }
+            if( w==11 )
+            {
+                r = -1.263e+01;
+            }
+            if( w==10 )
+            {
+                r = -1.287e+01;
+            }
+            if( w==9 )
+            {
+                r = -1.314e+01;
+            }
+            if( w==8 )
+            {
+                r = -1.342e+01;
+            }
+            if( w==7 )
+            {
+                r = -1.369e+01;
+            }
+            if( w==6 )
+            {
+                r = -1.400e+01;
+            }
+            if( w==5 )
+            {
+                r = -1.433e+01;
+            }
+            if( w==4 )
+            {
+                r = -1.469e+01;
+            }
+            if( w==3 )
+            {
+                r = -1.503e+01;
+            }
+            if( w==2 )
+            {
+                r = -1.554e+01;
+            }
+            if( w==1 )
+            {
+                r = -1.594e+01;
+            }
+            if( w<=0 )
+            {
+                r = -1.664e+01;
+            }
+            result = r;
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 25)
+        *************************************************************************/
+        private static double w25(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -5.150509e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.695528e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.437637e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -2.611906e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -7.625722e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -2.579892e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -1.086876e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -2.906543e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -2.354881e-03, ref tj, ref tj1, ref result);
+            wcheb(x, 1.007195e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -8.437327e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 26)
+        *************************************************************************/
+        private static double w26(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -5.117622e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.635159e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.395167e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -2.382823e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -6.531987e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -2.060112e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -8.203697e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.516523e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.431364e-03, ref tj, ref tj1, ref result);
+            wcheb(x, 6.384553e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -3.238369e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 27)
+        *************************************************************************/
+        private static double w27(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -5.089731e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.584248e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.359966e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -2.203696e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -5.753344e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -1.761891e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -7.096897e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.419108e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.581214e-03, ref tj, ref tj1, ref result);
+            wcheb(x, 3.033766e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -5.901441e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 28)
+        *************************************************************************/
+        private static double w28(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -5.065046e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.539163e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.328939e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -2.046376e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -5.061515e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -1.469271e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -5.711578e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -8.389153e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -1.250575e-03, ref tj, ref tj1, ref result);
+            wcheb(x, 4.047245e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -5.128555e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 29)
+        *************************************************************************/
+        private static double w29(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -5.043413e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.499756e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.302137e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.915129e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -4.516329e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -1.260064e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -4.817269e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -5.478130e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -1.111668e-03, ref tj, ref tj1, ref result);
+            wcheb(x, 4.093451e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -5.135860e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 30)
+        *************************************************************************/
+        private static double w30(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -5.024071e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.464515e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.278342e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.800030e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -4.046294e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -1.076162e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -3.968677e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.911679e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -8.619185e-04, ref tj, ref tj1, ref result);
+            wcheb(x, 5.125362e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -3.984370e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 40)
+        *************************************************************************/
+        private static double w40(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -4.904809e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.248327e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.136698e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.170982e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -1.824427e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -3.888648e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.344929e-03, ref tj, ref tj1, ref result);
+            wcheb(x, 2.790407e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -4.619858e-04, ref tj, ref tj1, ref result);
+            wcheb(x, 3.359121e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -2.883026e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 60)
+        *************************************************************************/
+        private static double w60(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -4.809656e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -5.077191e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -1.029402e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -7.507931e-02, ref tj, ref tj1, ref result);
+            wcheb(x, -6.506226e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -1.391278e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -4.263635e-04, ref tj, ref tj1, ref result);
+            wcheb(x, 2.302271e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -2.384348e-04, ref tj, ref tj1, ref result);
+            wcheb(x, 1.865587e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -1.622355e-04, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 120)
+        *************************************************************************/
+        private static double w120(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -4.729426e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -4.934426e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -9.433231e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -4.492504e-02, ref tj, ref tj1, ref result);
+            wcheb(x, 1.673948e-05, ref tj, ref tj1, ref result);
+            wcheb(x, -6.077014e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -7.215768e-05, ref tj, ref tj1, ref result);
+            wcheb(x, 9.086734e-05, ref tj, ref tj1, ref result);
+            wcheb(x, -8.447980e-05, ref tj, ref tj1, ref result);
+            wcheb(x, 6.705028e-05, ref tj, ref tj1, ref result);
+            wcheb(x, -5.828507e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S, 200)
+        *************************************************************************/
+        private static double w200(double s)
+        {
+            double result = 0;
+            double x = 0;
+            double tj = 0;
+            double tj1 = 0;
+
+            result = 0;
+            x = Math.Min(2*(s-0.000000e+00)/4.000000e+00-1, 1.0);
+            tj = 1;
+            tj1 = x;
+            wcheb(x, -4.700240e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -4.883080e+00, ref tj, ref tj1, ref result);
+            wcheb(x, -9.132168e-01, ref tj, ref tj1, ref result);
+            wcheb(x, -3.512684e-02, ref tj, ref tj1, ref result);
+            wcheb(x, 1.726342e-03, ref tj, ref tj1, ref result);
+            wcheb(x, -5.189796e-04, ref tj, ref tj1, ref result);
+            wcheb(x, -1.628659e-06, ref tj, ref tj1, ref result);
+            wcheb(x, 4.261786e-05, ref tj, ref tj1, ref result);
+            wcheb(x, -4.002498e-05, ref tj, ref tj1, ref result);
+            wcheb(x, 3.146287e-05, ref tj, ref tj1, ref result);
+            wcheb(x, -2.727576e-05, ref tj, ref tj1, ref result);
+            return result;
+        }
+
+
+        /*************************************************************************
+        Tail(S,N), S>=0
+        *************************************************************************/
+        private static double wsigma(double s,
+            int n)
+        {
+            double result = 0;
+            double f0 = 0;
+            double f1 = 0;
+            double f2 = 0;
+            double f3 = 0;
+            double f4 = 0;
+            double x0 = 0;
+            double x1 = 0;
+            double x2 = 0;
+            double x3 = 0;
+            double x4 = 0;
+            double x = 0;
+
+            if( n==5 )
+            {
+                result = w5(s);
+            }
+            if( n==6 )
+            {
+                result = w6(s);
+            }
+            if( n==7 )
+            {
+                result = w7(s);
+            }
+            if( n==8 )
+            {
+                result = w8(s);
+            }
+            if( n==9 )
+            {
+                result = w9(s);
+            }
+            if( n==10 )
+            {
+                result = w10(s);
+            }
+            if( n==11 )
+            {
+                result = w11(s);
+            }
+            if( n==12 )
+            {
+                result = w12(s);
+            }
+            if( n==13 )
+            {
+                result = w13(s);
+            }
+            if( n==14 )
+            {
+                result = w14(s);
+            }
+            if( n==15 )
+            {
+                result = w15(s);
+            }
+            if( n==16 )
+            {
+                result = w16(s);
+            }
+            if( n==17 )
+            {
+                result = w17(s);
+            }
+            if( n==18 )
+            {
+                result = w18(s);
+            }
+            if( n==19 )
+            {
+                result = w19(s);
+            }
+            if( n==20 )
+            {
+                result = w20(s);
+            }
+            if( n==21 )
+            {
+                result = w21(s);
+            }
+            if( n==22 )
+            {
+                result = w22(s);
+            }
+            if( n==23 )
+            {
+                result = w23(s);
+            }
+            if( n==24 )
+            {
+                result = w24(s);
+            }
+            if( n==25 )
+            {
+                result = w25(s);
+            }
+            if( n==26 )
+            {
+                result = w26(s);
+            }
+            if( n==27 )
+            {
+                result = w27(s);
+            }
+            if( n==28 )
+            {
+                result = w28(s);
+            }
+            if( n==29 )
+            {
+                result = w29(s);
+            }
+            if( n==30 )
+            {
+                result = w30(s);
+            }
+            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);
+                f1 = ((x-x0)*f1-(x-x1)*f0)/(x1-x0);
+                f2 = ((x-x0)*f2-(x-x2)*f0)/(x2-x0);
+                f3 = ((x-x0)*f3-(x-x3)*f0)/(x3-x0);
+                f4 = ((x-x0)*f4-(x-x4)*f0)/(x4-x0);
+                f2 = ((x-x1)*f2-(x-x2)*f1)/(x2-x1);
+                f3 = ((x-x1)*f3-(x-x3)*f1)/(x3-x1);
+                f4 = ((x-x1)*f4-(x-x4)*f1)/(x4-x1);
+                f3 = ((x-x2)*f3-(x-x3)*f2)/(x3-x2);
+                f4 = ((x-x2)*f4-(x-x4)*f2)/(x4-x2);
+                f4 = ((x-x3)*f4-(x-x4)*f3)/(x4-x3);
+                result = f4;
+            }
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/xblas.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/xblas.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/ALGLIB-2.1.2.2591/xblas.cs	(revision 2645)
@@ -0,0 +1,216 @@
+
+using System;
+
+namespace alglib
+{
+    public class xblas
+    {
+        /*************************************************************************
+        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/B to fit in double (about 1 ulp).
+
+          -- ALGLIB --
+             Copyright 24.08.2009 by Bochkanov Sergey
+        *************************************************************************/
+        public static void xdot(ref double[] a,
+            ref double[] b,
+            int n,
+            ref double[] temp,
+            ref double r,
+            ref double rerr)
+        {
+            int i = 0;
+            int k = 0;
+            int ks = 0;
+            double mx = 0;
+            double v = 0;
+            double v1 = 0;
+            double v2 = 0;
+            double s = 0;
+            double ln2 = 0;
+            double chunk = 0;
+            double invchunk = 0;
+            bool allzeros = new bool();
+            int i_ = 0;
+
+            
+            //
+            // special cases:
+            // * N=0
+            // * N is too large to use integer arithmetics
+            //
+            if( n==0 )
+            {
+                r = 0;
+                rerr = 0;
+                return;
+            }
+            System.Diagnostics.Debug.Assert(n<536870912, "XDot: N is too large!");
+            
+            //
+            // Prepare
+            //
+            ln2 = Math.Log(2);
+            
+            //
+            // calculate pairwise products vector TEMP
+            // (relative precision of TEMP - almost full)
+            // find infinity-norm of products vector
+            //
+            mx = 0;
+            for(i=0; i<=n-1; i++)
+            {
+                v = a[i]*b[i];
+                temp[i] = v;
+                mx = Math.Max(mx, Math.Abs(v));
+            }
+            if( (double)(mx)==(double)(0) )
+            {
+                r = 0;
+                rerr = 0;
+                return;
+            }
+            rerr = mx*AP.Math.MachineEpsilon;
+            
+            //
+            // 1. find S such that 0.5<=S*MX<1
+            // 2. multiply TEMP by S, so task is normalized in some sense
+            // 3. S:=1/S so we can obtain original vector multiplying by S
+            //
+            k = (int)Math.Round(Math.Log(mx)/ln2);
+            s = xfastpow(2, -k);
+            while( (double)(s*mx)>=(double)(1) )
+            {
+                s = 0.5*s;
+            }
+            while( (double)(s*mx)<(double)(0.5) )
+            {
+                s = 2*s;
+            }
+            for(i_=0; i_<=n-1;i_++)
+            {
+                temp[i_] = s*temp[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)(Math.Log((double)(536870912)/(double)(n))/ln2);
+            chunk = xfastpow(2, k);
+            if( (double)(chunk)<(double)(2) )
+            {
+                chunk = 2;
+            }
+            invchunk = 1/chunk;
+            
+            //
+            // calculate result
+            //
+            r = 0;
+            for(i_=0; i_<=n-1;i_++)
+            {
+                temp[i_] = chunk*temp[i_];
+            }
+            while( true )
+            {
+                s = s*invchunk;
+                allzeros = true;
+                ks = 0;
+                for(i=0; i<=n-1; i++)
+                {
+                    v = temp[i];
+                    k = (int)(v);
+                    if( (double)(v)!=(double)(k) )
+                    {
+                        allzeros = false;
+                    }
+                    temp[i] = chunk*(v-k);
+                    ks = ks+k;
+                }
+                r = r+s*ks;
+                v = Math.Abs(r);
+                if( allzeros | (double)(s*n+mx)==(double)(mx) )
+                {
+                    break;
+                }
+            }
+            
+            //
+            // correct error
+            //
+            rerr = Math.Max(rerr, Math.Abs(r)*AP.Math.MachineEpsilon);
+        }
+
+
+        private static double xfastpow(double r,
+            int n)
+        {
+            double result = 0;
+
+            if( n>0 )
+            {
+                if( n%2==0 )
+                {
+                    result = AP.Math.Sqr(xfastpow(r, n/2));
+                }
+                else
+                {
+                    result = r*xfastpow(r, n-1);
+                }
+                return result;
+            }
+            if( n==0 )
+            {
+                result = 1;
+            }
+            if( n<0 )
+            {
+                result = xfastpow(1/r, -n);
+            }
+            return result;
+        }
+
+
+        private static double xfrac(double r)
+        {
+            double result = 0;
+            int i = 0;
+
+            if( (double)(r)==(double)(0) )
+            {
+                result = 0;
+                return result;
+            }
+            if( (double)(r)<(double)(0) )
+            {
+                result = -1;
+                r = -r;
+            }
+            else
+            {
+                result = 1;
+            }
+            result = result*(r-(int)Math.Floor(r));
+            return result;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/ALGLIB License.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/ALGLIB License.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/ALGLIB License.txt	(revision 2645)
@@ -0,0 +1,16 @@
+﻿Copyright (c) 2003-2009 Sergey Bochkanov (ALGLIB project).
+
+>>> LICENSE >>>
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation (www.fsf.org); either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+A copy of the GNU General Public License is available at
+http://www.fsf.org/licensing/licenses
+
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591.csproj	(revision 2645)
@@ -0,0 +1,122 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{B6C53341-86C0-4063-87E2-F573EFE51132}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.ALGLIB</RootNamespace>
+    <AssemblyName>HeuristicLab.ALGLIB-2.1.2.2591</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HeuristicLabAlgLibPlugin.cs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ALGLIB-2.1.2.2591\ALGLIB-2.1.2.2591.csproj">
+      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
+      <Name>ALGLIB-2.1.2.2591</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="ALGLIB License.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/HeuristicLabAlgLibPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/HeuristicLabAlgLibPlugin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/HeuristicLabAlgLibPlugin.cs	(revision 2645)
@@ -0,0 +1,35 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2009 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.ALGLIB {
+  [Plugin("HeuristicLab.ALGLIB-2.1.2.2591")]  
+  [PluginFile("HeuristicLab.ALGLIB-2.1.2.2591.dll", PluginFileType.Assembly)]
+  [PluginFile("ALGLIB-2.1.2.2591.dll", PluginFileType.Assembly)]
+  [PluginFile("ALGLIB License.txt", PluginFileType.License)]
+  public class HeuristicLabAlgLibPlugin : PluginBase {
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/Properties/AssemblyInfo.frame
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/Properties/AssemblyInfo.frame	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/2.1.2.2591/HeuristicLab.ALGLIB-2.1.2.2591/Properties/AssemblyInfo.frame	(revision 2645)
@@ -0,0 +1,38 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.ALGLIB")]
+[assembly: AssemblyDescription("Provides an interface to ALGLIB")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3f5083f8-2738-4573-b230-e9928ef61e6b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("2.1.2.2591")]
+[assembly: AssemblyFileVersion("2.1.2.2591")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/HeuristicLab.LibSVM-1.6.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/HeuristicLab.LibSVM-1.6.3.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/HeuristicLab.LibSVM-1.6.3.csproj	(revision 2645)
@@ -0,0 +1,123 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{89B50302-9CEE-4D13-9779-633EADCAE624}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.LibSVM</RootNamespace>
+    <AssemblyName>HeuristicLab.LibSVM-1.6.3</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\HeuristicLab.LibSVM-1.6.3.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.LibSVM-1.6.3.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.LibSVM-1.6.3.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HeuristicLabLibSVMPlugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="LibSVM License.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\LibSVM-1.6.3\LibSVM-1.6.3.csproj">
+      <Project>{A16F23B5-FB62-499E-A831-26953AA56FE2}</Project>
+      <Name>LibSVM-1.6.3</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/HeuristicLabLibSVMPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/HeuristicLabLibSVMPlugin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/HeuristicLabLibSVMPlugin.cs	(revision 2645)
@@ -0,0 +1,15 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.LibSVM {
+  [Plugin("HeuristicLab.LibSVM-1.6.3")]
+  [PluginFile("HeuristicLab.LibSVM-1.6.3.dll", PluginFileType.Assembly)]
+  [PluginFile("LibSVM-1.6.3.dll", PluginFileType.Assembly)]
+  [PluginFile("LibSVM License.txt",PluginFileType.License)]
+  public class HeuristicLabWinFormsUIPlugin : PluginBase {
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/LibSVM license.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/LibSVM license.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/LibSVM license.txt	(revision 2645)
@@ -0,0 +1,280 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/Properties/AssemblyInfo.frame
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/Properties/AssemblyInfo.frame	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/HeuristicLab.LibSVM-1.6.3/Properties/AssemblyInfo.frame	(revision 2645)
@@ -0,0 +1,38 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.LibSVM")]
+[assembly: AssemblyDescription("Transport plugin for LibSVM")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3f5083f8-2738-4573-b230-e9928ef61e6b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.6.3")]
+[assembly: AssemblyFileVersion("1.6.3")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Cache.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Cache.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Cache.cs	(revision 2645)
@@ -0,0 +1,161 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+
+namespace SVM
+{
+    internal class Cache
+    {
+        private int _count;
+        private long _size;
+
+        private sealed class head_t
+        {
+            public head_t(Cache enclosingInstance)
+            {
+                _enclosingInstance = enclosingInstance;
+            }
+            private Cache _enclosingInstance;
+            public Cache EnclosingInstance
+            {
+                get
+                {
+                    return _enclosingInstance;
+                }
+            }
+            internal head_t prev, next; // a cicular list
+            internal float[] data;
+            internal int len; // data[0,len) is cached in this entry
+        }
+
+        private head_t[] head;
+        private head_t lru_head;
+
+        public Cache(int count, long size)
+        {
+            _count = count;
+            _size = size;
+            head = new head_t[_count];
+            for (int i = 0; i < _count; i++)
+                head[i] = new head_t(this);
+            _size /= 4;
+            _size -= _count * (16 / 4); // sizeof(head_t) == 16
+            lru_head = new head_t(this);
+            lru_head.next = lru_head.prev = lru_head;
+        }
+
+        private void lru_delete(head_t h)
+        {
+            // delete from current location
+            h.prev.next = h.next;
+            h.next.prev = h.prev;
+        }
+
+        private void lru_insert(head_t h)
+        {
+            // insert to last position
+            h.next = lru_head;
+            h.prev = lru_head.prev;
+            h.prev.next = h;
+            h.next.prev = h;
+        }
+
+        private static void swap<T>(ref T lhs, ref T rhs)
+        {
+            T tmp = lhs;
+            lhs = rhs;
+            rhs = tmp;
+        }
+
+        // request data [0,len)
+        // return some position p where [p,len) need to be filled
+        // (p >= len if nothing needs to be filled)
+        // java: simulate pointer using single-element array
+        public int GetData(int index, ref float[] data, int len)
+        {
+            head_t h = head[index];
+            if (h.len > 0)
+                lru_delete(h);
+            int more = len - h.len;
+
+            if (more > 0)
+            {
+                // free old space
+                while (_size < more)
+                {
+                    head_t old = lru_head.next;
+                    lru_delete(old);
+                    _size += old.len;
+                    old.data = null;
+                    old.len = 0;
+                }
+
+                // allocate new space
+                float[] new_data = new float[len];
+                if (h.data != null)
+                    Array.Copy(h.data, 0, new_data, 0, h.len);
+                h.data = new_data;
+                _size -= more;
+                swap(ref h.len, ref len);
+            }
+
+            lru_insert(h);
+            data = h.data;
+            return len;
+        }
+
+        public void SwapIndex(int i, int j)
+        {
+            if (i == j)
+                return;
+
+            if (head[i].len > 0)
+                lru_delete(head[i]);
+            if (head[j].len > 0)
+                lru_delete(head[j]);
+            swap(ref head[i].data, ref head[j].data);
+            swap(ref head[i].len, ref head[j].len);
+            if (head[i].len > 0)
+                lru_insert(head[i]);
+            if (head[j].len > 0)
+                lru_insert(head[j]);
+
+            if (i > j)
+                swap(ref i, ref j);
+
+            for (head_t h = lru_head.next; h != lru_head; h = h.next)
+            {
+                if (h.len > i)
+                {
+                    if (h.len > j)
+                        swap(ref h.data[i], ref h.data[j]);
+                    else
+                    {
+                        // give up
+                        lru_delete(h);
+                        _size += h.len;
+                        h.data = null;
+                        h.len = 0;
+                    }
+                }
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/GaussianTransform.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/GaussianTransform.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/GaussianTransform.cs	(revision 2645)
@@ -0,0 +1,209 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Globalization;
+using System.Threading;
+
+namespace SVM
+{
+    /// <summary>
+    /// A transform which learns the mean and variance of a sample set and uses these to transform new data
+    /// so that it has zero mean and unit variance.
+    /// </summary>
+    public class GaussianTransform : IRangeTransform
+    {
+        private double[] _means;
+        private double[] _stddevs;
+
+        /// <summary>
+        /// Determines the Gaussian transform for the provided problem.
+        /// </summary>
+        /// <param name="prob">The Problem to analyze</param>
+        /// <returns>The Gaussian transform for the problem</returns>
+        public static GaussianTransform Compute(Problem prob)
+        {
+            int[] counts = new int[prob.MaxIndex];
+            double[] means = new double[prob.MaxIndex];
+            foreach (Node[] sample in prob.X)
+            {
+                for (int i = 0; i < sample.Length; i++)
+                {
+                    means[sample[i].Index-1] += sample[i].Value;
+                    counts[sample[i].Index-1]++;
+                }
+            }
+            for (int i = 0; i < prob.MaxIndex; i++)
+            {
+                if (counts[i] == 0)
+                    counts[i] = 2;
+                means[i] /= counts[i];
+            }
+
+            double[] stddevs = new double[prob.MaxIndex];
+            foreach (Node[] sample in prob.X)
+            {
+                for (int i = 0; i < sample.Length; i++)
+                {
+                    double diff = sample[i].Value - means[sample[i].Index - 1];
+                    stddevs[sample[i].Index - 1] += diff * diff;
+                }
+            }
+            for (int i = 0; i < prob.MaxIndex; i++)
+            {
+                if (stddevs[i] == 0)
+                    continue;
+                stddevs[i] /= (counts[i] - 1);
+                stddevs[i] = Math.Sqrt(stddevs[i]);
+            }
+
+            return new GaussianTransform(means, stddevs);
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="means">Means in each dimension</param>
+        /// <param name="stddevs">Standard deviation in each dimension</param>
+        public GaussianTransform(double[] means, double[] stddevs)
+        {
+            _means = means;
+            _stddevs = stddevs;
+        }
+
+        /// <summary>
+        /// Saves the transform to the disk.  The samples are not stored, only the 
+        /// statistics.
+        /// </summary>
+        /// <param name="stream">The destination stream</param>
+        /// <param name="transform">The transform</param>
+        public static void Write(Stream stream, GaussianTransform transform)
+        {
+            TemporaryCulture.Start();
+
+            StreamWriter output = new StreamWriter(stream);
+            output.WriteLine(transform._means.Length);
+            for (int i = 0; i < transform._means.Length; i++)
+                output.WriteLine("{0} {1}", transform._means[i], transform._stddevs[i]);
+            output.Flush();
+
+            TemporaryCulture.Stop();
+        }
+
+        /// <summary>
+        /// Reads a GaussianTransform from the provided stream.
+        /// </summary>
+        /// <param name="stream">The source stream</param>
+        /// <returns>The transform</returns>
+        public static GaussianTransform Read(Stream stream)
+        {
+            TemporaryCulture.Start();
+
+            StreamReader input = new StreamReader(stream);
+            int length = int.Parse(input.ReadLine(), CultureInfo.InvariantCulture);
+            double[] means = new double[length];
+            double[] stddevs = new double[length];
+            for (int i = 0; i < length; i++)
+            {
+                string[] parts = input.ReadLine().Split();
+                means[i] = double.Parse(parts[0], CultureInfo.InvariantCulture);
+                stddevs[i] = double.Parse(parts[1], CultureInfo.InvariantCulture);
+            }
+
+            TemporaryCulture.Stop();
+
+            return new GaussianTransform(means, stddevs);
+        }
+
+        /// <summary>
+        /// Saves the transform to the disk.  The samples are not stored, only the 
+        /// statistics.
+        /// </summary>
+        /// <param name="filename">The destination filename</param>
+        /// <param name="transform">The transform</param>
+        public static void Write(string filename, GaussianTransform transform)
+        {
+            FileStream output = File.Open(filename, FileMode.Create);
+            try
+            {
+                Write(output, transform);
+            }
+            finally
+            {
+                output.Close();
+            }
+        }
+
+        /// <summary>
+        /// Reads a GaussianTransform from the provided stream.
+        /// </summary>
+        /// <param name="filename">The source filename</param>
+        /// <returns>The transform</returns>
+        public static GaussianTransform Read(string filename)
+        {
+            FileStream input = File.Open(filename, FileMode.Open);
+            try
+            {
+                return Read(input);
+            }
+            finally
+            {
+                input.Close();
+            }
+        }
+
+        #region IRangeTransform Members
+
+        /// <summary>
+        /// Transform the input value using the transform stored for the provided index.
+        /// </summary>
+        /// <param name="input">Input value</param>
+        /// <param name="index">Index of the transform to use</param>
+        /// <returns>The transformed value</returns>
+        public double Transform(double input, int index)
+        {
+            index--;
+            if (_stddevs[index] == 0)
+                return 0;
+            double diff = input - _means[index];
+            diff /= _stddevs[index];
+            return diff;
+        }
+        /// <summary>
+        /// Transforms the input array.
+        /// </summary>
+        /// <param name="input">The array to transform</param>
+        /// <returns>The transformed array</returns>
+        public Node[] Transform(Node[] input)
+        {
+            Node[] output = new Node[input.Length];
+            for (int i = 0; i < output.Length; i++)
+            {
+                int index = input[i].Index;
+                double value = input[i].Value;
+                output[i] = new Node(index, Transform(value, index));
+            }
+            return output;
+        }
+
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/IRangeTransform.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/IRangeTransform.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/IRangeTransform.cs	(revision 2645)
@@ -0,0 +1,41 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+namespace SVM
+{
+    /// <summary>
+    /// Interface implemented by range transforms.
+    /// </summary>
+    public interface IRangeTransform
+    {
+        /// <summary>
+        /// Transform the input value using the transform stored for the provided index.
+        /// </summary>
+        /// <param name="input">Input value</param>
+        /// <param name="index">Index of the transform to use</param>
+        /// <returns>The transformed value</returns>
+        double Transform(double input, int index);
+        /// <summary>
+        /// Transforms the input array.
+        /// </summary>
+        /// <param name="input">The array to transform</param>
+        /// <returns>The transformed array</returns>
+        Node[] Transform(Node[] input);
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Kernel.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Kernel.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Kernel.cs	(revision 2645)
@@ -0,0 +1,226 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SVM
+{
+    internal interface IQMatrix
+    {
+        float[] GetQ(int column, int len);
+        float[] GetQD();
+        void SwapIndex(int i, int j);
+    }
+
+    internal abstract class Kernel : IQMatrix
+    {
+        private Node[][] _x;
+        private double[] _xSquare;
+
+        private KernelType _kernelType;
+        private int _degree;
+        private double _gamma;
+        private double _coef0;
+
+        public abstract float[] GetQ(int column, int len);
+        public abstract float[] GetQD();
+
+        public virtual void SwapIndex(int i, int j)
+        {
+            _x.SwapIndex(i, j);
+
+            if (_xSquare != null)
+            {
+                _xSquare.SwapIndex(i, j);
+            }
+        }
+
+        private static double powi(double value, int times)
+        {
+            double tmp = value, ret = 1.0;
+
+            for (int t = times; t > 0; t /= 2)
+            {
+                if (t % 2 == 1) ret *= tmp;
+                tmp = tmp * tmp;
+            }
+            return ret;
+        }
+
+        public double KernelFunction(int i, int j)
+        {
+            switch (_kernelType)
+            {
+                case KernelType.LINEAR:
+                    return dot(_x[i], _x[j]);
+                case KernelType.POLY:
+                    return powi(_gamma * dot(_x[i], _x[j]) + _coef0, _degree);
+                case KernelType.RBF:
+                    return Math.Exp(-_gamma * (_xSquare[i] + _xSquare[j] - 2 * dot(_x[i], _x[j])));
+                case KernelType.SIGMOID:
+                    return Math.Tanh(_gamma * dot(_x[i], _x[j]) + _coef0);
+                case KernelType.PRECOMPUTED:
+                    return _x[i][(int)(_x[j][0].Value)].Value;
+                default:
+                    return 0;
+            }
+        }
+
+        public Kernel(int l, Node[][] x_, Parameter param)
+        {
+            _kernelType = param.KernelType;
+            _degree = param.Degree;
+            _gamma = param.Gamma;
+            _coef0 = param.Coefficient0;
+
+            _x = (Node[][])x_.Clone();
+
+            if (_kernelType == KernelType.RBF)
+            {
+                _xSquare = new double[l];
+                for (int i = 0; i < l; i++)
+                    _xSquare[i] = dot(_x[i], _x[i]);
+            }
+            else _xSquare = null;
+        }
+
+        private static double dot(Node[] xNodes, Node[] yNodes)
+        {
+            double sum = 0;
+            int xlen = xNodes.Length;
+            int ylen = yNodes.Length;
+            int i = 0;
+            int j = 0;
+            Node x = xNodes[0];
+            Node y = yNodes[0];
+            while (true)
+            {
+                if (x._index == y._index)
+                {
+                    sum += x._value * y._value;
+                    i++;
+                    j++;
+                    if (i < xlen && j < ylen)
+                    {
+                        x = xNodes[i];
+                        y = yNodes[j];
+                    }
+                    else if (i < xlen)
+                    {
+                        x = xNodes[i];
+                        break;
+                    }
+                    else if (j < ylen)
+                    {
+                        y = yNodes[j];
+                        break;
+                    }
+                    else break;
+                }
+                else
+                {
+                    if (x._index > y._index)
+                    {
+                        ++j;
+                        if (j < ylen)
+                            y = yNodes[j];
+                        else break;
+                    }
+                    else
+                    {
+                        ++i;
+                        if (i < xlen)
+                            x = xNodes[i];
+                        else break;
+                    }
+                }
+            }
+            return sum;
+        }
+
+        private static double computeSquaredDistance(Node[] xNodes, Node[] yNodes)
+        {
+            Node x = xNodes[0];
+            Node y = yNodes[0];
+            int xLength = xNodes.Length;
+            int yLength = yNodes.Length;
+            int xIndex = 0;
+            int yIndex = 0;
+            double sum = 0;
+
+            while (true)
+            {
+                if (x._index == y._index)
+                {
+                    double d = x._value - y._value;
+                    sum += d * d;
+                    xIndex++;
+                    yIndex++;
+                    if (xIndex < xLength && yIndex < yLength)
+                    {
+                        x = xNodes[xIndex];
+                        y = yNodes[yIndex];
+                    }
+                    else if(xIndex < xLength){
+                        x = xNodes[xIndex];
+                        break;
+                    }
+                    else if(yIndex < yLength){
+                        y = yNodes[yIndex];
+                        break;
+                    }else break;
+                }
+                else if (x._index > y._index)
+                {
+                    sum += y._value * y._value;
+                    if (++yIndex < yLength)
+                        y = yNodes[yIndex];
+                    else break;
+                }
+                else
+                {
+                    sum += x._value * x._value;
+                    if (++xIndex < xLength)
+                        x = xNodes[xIndex];
+                    else break;
+                }
+            }
+
+            for (; xIndex < xLength; xIndex++)
+            {
+                double d = xNodes[xIndex]._value;
+                sum += d * d;
+            }
+
+            for (; yIndex < yLength; yIndex++)
+            {
+                double d = yNodes[yIndex]._value;
+                sum += d * d;
+            }
+
+            return sum;
+        }
+
+        public static double KernelFunction(Node[] x, Node[] y, Parameter param)
+        {
+            switch (param.KernelType)
+            {
+                case KernelType.LINEAR:
+                    return dot(x, y);
+                case KernelType.POLY:
+                    return powi(param.Degree * dot(x, y) + param.Coefficient0, param.Degree);
+                case KernelType.RBF:
+                    {
+                        double sum = computeSquaredDistance(x, y);
+                        return Math.Exp(-param.Gamma * sum);
+                    }
+                case KernelType.SIGMOID:
+                    return Math.Tanh(param.Gamma * dot(x, y) + param.Coefficient0);
+                case KernelType.PRECOMPUTED:
+                    return x[(int)(y[0].Value)].Value;
+                default:
+                    return 0;
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/LibSVM-1.6.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/LibSVM-1.6.3.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/LibSVM-1.6.3.csproj	(revision 2645)
@@ -0,0 +1,118 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{A16F23B5-FB62-499E-A831-26953AA56FE2}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>SVM</RootNamespace>
+    <AssemblyName>LibSVM-1.6.3</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <DocumentationFile>bin\x64\Release\LibSVM-1.6.3.xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Kernel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Cache.cs" />
+    <Compile Include="GaussianTransform.cs" />
+    <Compile Include="IRangeTransform.cs" />
+    <Compile Include="Model.cs" />
+    <Compile Include="Node.cs" />
+    <Compile Include="Parameter.cs" />
+    <Compile Include="ParameterSelection.cs" />
+    <Compile Include="PerformanceEvaluator.cs" />
+    <Compile Include="PrecomputedKernel.cs" />
+    <Compile Include="Prediction.cs" />
+    <Compile Include="Problem.cs" />
+    <Compile Include="RangeTransform.cs" />
+    <Compile Include="Scaling.cs" />
+    <Compile Include="Solver.cs" />
+    <Compile Include="SVMExtensions.cs" />
+    <Compile Include="TemporaryCulture.cs" />
+    <Compile Include="Training.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>
+    </PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/LibSVM-1.6.3.csproj.user
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/LibSVM-1.6.3.csproj.user	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/LibSVM-1.6.3.csproj.user	(revision 2645)
@@ -0,0 +1,5 @@
+﻿<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <ProjectView>ShowAllFiles</ProjectView>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Model.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Model.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Model.cs	(revision 2645)
@@ -0,0 +1,438 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Globalization;
+
+namespace SVM {
+  /// <summary>
+  /// Encapsulates an SVM Model.
+  /// </summary>
+  [Serializable]
+  public class Model {
+    private Parameter _parameter;
+    private int _numberOfClasses;
+    private int _supportVectorCount;
+    private Node[][] _supportVectors;
+    private double[][] _supportVectorCoefficients;
+    private double[] _rho;
+    private double[] _pairwiseProbabilityA;
+    private double[] _pairwiseProbabilityB;
+
+    private int[] _classLabels;
+    private int[] _numberOfSVPerClass;
+
+    internal Model() {
+    }
+
+    /// <summary>
+    /// Parameter object.
+    /// </summary>
+    public Parameter Parameter {
+      get {
+        return _parameter;
+      }
+      set {
+        _parameter = value;
+      }
+    }
+
+    /// <summary>
+    /// Number of classes in the model.
+    /// </summary>
+    public int NumberOfClasses {
+      get {
+        return _numberOfClasses;
+      }
+      set {
+        _numberOfClasses = value;
+      }
+    }
+
+    /// <summary>
+    /// Total number of support vectors.
+    /// </summary>
+    public int SupportVectorCount {
+      get {
+        return _supportVectorCount;
+      }
+      set {
+        _supportVectorCount = value;
+      }
+    }
+
+    /// <summary>
+    /// The support vectors.
+    /// </summary>
+    public Node[][] SupportVectors {
+      get {
+        return _supportVectors;
+      }
+      set {
+        _supportVectors = value;
+      }
+    }
+
+    /// <summary>
+    /// The coefficients for the support vectors.
+    /// </summary>
+    public double[][] SupportVectorCoefficients {
+      get {
+        return _supportVectorCoefficients;
+      }
+      set {
+        _supportVectorCoefficients = value;
+      }
+    }
+
+    /// <summary>
+    /// Rho values.
+    /// </summary>
+    public double[] Rho {
+      get {
+        return _rho;
+      }
+      set {
+        _rho = value;
+      }
+    }
+
+    /// <summary>
+    /// First pairwise probability.
+    /// </summary>
+    public double[] PairwiseProbabilityA {
+      get {
+        return _pairwiseProbabilityA;
+      }
+      set {
+        _pairwiseProbabilityA = value;
+      }
+    }
+
+    /// <summary>
+    /// Second pairwise probability.
+    /// </summary>
+    public double[] PairwiseProbabilityB {
+      get {
+        return _pairwiseProbabilityB;
+      }
+      set {
+        _pairwiseProbabilityB = value;
+      }
+    }
+
+    // for classification only
+
+    /// <summary>
+    /// Class labels.
+    /// </summary>
+    public int[] ClassLabels {
+      get {
+        return _classLabels;
+      }
+      set {
+        _classLabels = value;
+      }
+    }
+
+    /// <summary>
+    /// Number of support vectors per class.
+    /// </summary>
+    public int[] NumberOfSVPerClass {
+      get {
+        return _numberOfSVPerClass;
+      }
+      set {
+        _numberOfSVPerClass = value;
+      }
+    }
+
+    /// <summary>
+    /// Reads a Model from the provided file.
+    /// </summary>
+    /// <param name="filename">The name of the file containing the Model</param>
+    /// <returns>the Model</returns>
+    public static Model Read(string filename) {
+      FileStream input = File.OpenRead(filename);
+      try {
+        return Read(input);
+      }
+      finally {
+        input.Close();
+      }
+    }
+
+    public static Model Read(Stream stream) {
+      return Read(new StreamReader(stream));
+    }
+
+    /// <summary>
+    /// Reads a Model from the provided stream.
+    /// </summary>
+    /// <param name="stream">The stream from which to read the Model.</param>
+    /// <returns>the Model</returns>
+    public static Model Read(TextReader input) {
+      TemporaryCulture.Start();
+
+      // read parameters
+
+      Model model = new Model();
+      Parameter param = new Parameter();
+      model.Parameter = param;
+      model.Rho = null;
+      model.PairwiseProbabilityA = null;
+      model.PairwiseProbabilityB = null;
+      model.ClassLabels = null;
+      model.NumberOfSVPerClass = null;
+
+      bool headerFinished = false;
+      while (!headerFinished) {
+        string line = input.ReadLine();
+        string cmd, arg;
+        int splitIndex = line.IndexOf(' ');
+        if (splitIndex >= 0) {
+          cmd = line.Substring(0, splitIndex);
+          arg = line.Substring(splitIndex + 1);
+        } else {
+          cmd = line;
+          arg = "";
+        }
+        // arg = arg.ToLower(); (transforms double NaN or Infinity values to incorrect format [gkronber])
+
+        int i, n;
+        switch (cmd) {
+          case "svm_type":
+            param.SvmType = (SvmType)Enum.Parse(typeof(SvmType), arg.ToUpper());
+            break;
+
+          case "kernel_type":
+            param.KernelType = (KernelType)Enum.Parse(typeof(KernelType), arg.ToUpper());
+            break;
+
+          case "degree":
+            param.Degree = int.Parse(arg);
+            break;
+
+          case "gamma":
+            param.Gamma = double.Parse(arg);
+            break;
+
+          case "coef0":
+            param.Coefficient0 = double.Parse(arg);
+            break;
+
+          case "nr_class":
+            model.NumberOfClasses = int.Parse(arg);
+            break;
+
+          case "total_sv":
+            model.SupportVectorCount = int.Parse(arg);
+            break;
+
+          case "rho":
+            n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
+            model.Rho = new double[n];
+            string[] rhoParts = arg.Split();
+            for (i = 0; i < n; i++)
+              model.Rho[i] = double.Parse(rhoParts[i]);
+            break;
+
+          case "label":
+            n = model.NumberOfClasses;
+            model.ClassLabels = new int[n];
+            string[] labelParts = arg.Split();
+            for (i = 0; i < n; i++)
+              model.ClassLabels[i] = int.Parse(labelParts[i]);
+            break;
+
+          case "probA":
+            n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
+            model.PairwiseProbabilityA = new double[n];
+            string[] probAParts = arg.Split();
+            for (i = 0; i < n; i++)
+              model.PairwiseProbabilityA[i] = double.Parse(probAParts[i]);
+            break;
+
+          case "probB":
+            n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
+            model.PairwiseProbabilityB = new double[n];
+            string[] probBParts = arg.Split();
+            for (i = 0; i < n; i++)
+              model.PairwiseProbabilityB[i] = double.Parse(probBParts[i]);
+            break;
+
+          case "nr_sv":
+            n = model.NumberOfClasses;
+            model.NumberOfSVPerClass = new int[n];
+            string[] nrsvParts = arg.Split();
+            for (i = 0; i < n; i++)
+              model.NumberOfSVPerClass[i] = int.Parse(nrsvParts[i]);
+            break;
+
+          case "SV":
+            headerFinished = true;
+            break;
+
+          default:
+            throw new Exception("Unknown text in model file");
+        }
+      }
+
+      // read sv_coef and SV
+
+      int m = model.NumberOfClasses - 1;
+      int l = model.SupportVectorCount;
+      model.SupportVectorCoefficients = new double[m][];
+      for (int i = 0; i < m; i++) {
+        model.SupportVectorCoefficients[i] = new double[l];
+      }
+      model.SupportVectors = new Node[l][];
+
+      for (int i = 0; i < l; i++) {
+        string[] parts = input.ReadLine().Trim().Split();
+
+        for (int k = 0; k < m; k++)
+          model.SupportVectorCoefficients[k][i] = double.Parse(parts[k]);
+        int n = parts.Length - m;
+        model.SupportVectors[i] = new Node[n];
+        for (int j = 0; j < n; j++) {
+          string[] nodeParts = parts[m + j].Split(':');
+          model.SupportVectors[i][j] = new Node();
+          model.SupportVectors[i][j].Index = int.Parse(nodeParts[0]);
+          model.SupportVectors[i][j].Value = double.Parse(nodeParts[1]);
+        }
+      }
+
+      TemporaryCulture.Stop();
+
+      return model;
+    }
+
+    /// <summary>
+    /// Writes a model to the provided filename.  This will overwrite any previous data in the file.
+    /// </summary>
+    /// <param name="filename">The desired file</param>
+    /// <param name="model">The Model to write</param>
+    public static void Write(string filename, Model model) {
+      FileStream stream = File.Open(filename, FileMode.Create);
+      try {
+        Write(stream, model);
+      }
+      finally {
+        stream.Close();
+      }
+    }
+
+    /// <summary>
+    /// Writes a model to the provided stream.
+    /// </summary>
+    /// <param name="stream">The output stream</param>
+    /// <param name="model">The model to write</param>
+    public static void Write(Stream stream, Model model) {
+      TemporaryCulture.Start();
+
+      StreamWriter output = new StreamWriter(stream);
+
+      Parameter param = model.Parameter;
+
+      output.Write("svm_type " + param.SvmType + Environment.NewLine);
+      output.Write("kernel_type " + param.KernelType + Environment.NewLine);
+
+      if (param.KernelType == KernelType.POLY)
+        output.Write("degree " + param.Degree.ToString("r") + Environment.NewLine);
+
+      if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.RBF || param.KernelType == KernelType.SIGMOID)
+        output.Write("gamma " + param.Gamma.ToString("r") + Environment.NewLine);
+
+      if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.SIGMOID)
+        output.Write("coef0 " + param.Coefficient0.ToString("r") + Environment.NewLine);
+
+      int nr_class = model.NumberOfClasses;
+      int l = model.SupportVectorCount;
+      output.Write("nr_class " + nr_class + Environment.NewLine);
+      output.Write("total_sv " + l + Environment.NewLine);
+
+      {
+        output.Write("rho");
+        for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+          output.Write(" " + model.Rho[i].ToString("r"));
+        output.Write(Environment.NewLine);
+      }
+
+      if (model.ClassLabels != null) {
+        output.Write("label");
+        for (int i = 0; i < nr_class; i++)
+          output.Write(" " + model.ClassLabels[i]);
+        output.Write(Environment.NewLine);
+      }
+
+      if (model.PairwiseProbabilityA != null)
+      // regression has probA only
+            {
+        output.Write("probA");
+        for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+          output.Write(" " + model.PairwiseProbabilityA[i].ToString("r"));
+        output.Write(Environment.NewLine);
+      }
+      if (model.PairwiseProbabilityB != null) {
+        output.Write("probB");
+        for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+          output.Write(" " + model.PairwiseProbabilityB[i].ToString("r"));
+        output.Write(Environment.NewLine);
+      }
+
+      if (model.NumberOfSVPerClass != null) {
+        output.Write("nr_sv");
+        for (int i = 0; i < nr_class; i++)
+          output.Write(" " + model.NumberOfSVPerClass[i].ToString("r"));
+        output.Write(Environment.NewLine);
+      }
+
+      output.WriteLine("SV");
+      double[][] sv_coef = model.SupportVectorCoefficients;
+      Node[][] SV = model.SupportVectors;
+
+      for (int i = 0; i < l; i++) {
+        for (int j = 0; j < nr_class - 1; j++)
+          output.Write(sv_coef[j][i].ToString("r") + " ");
+
+        Node[] p = SV[i];
+        if (p.Length == 0) {
+          output.WriteLine();
+          continue;
+        }
+        if (param.KernelType == KernelType.PRECOMPUTED)
+          output.Write("0:{0}", (int)p[0].Value);
+        else {
+          output.Write("{0}:{1}", p[0].Index, p[0].Value.ToString("r"));
+          for (int j = 1; j < p.Length; j++)
+            output.Write(" {0}:{1}", p[j].Index, p[j].Value.ToString("r"));
+        }
+        output.WriteLine();
+      }
+
+      output.Flush();
+
+      TemporaryCulture.Stop();
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Node.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Node.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Node.cs	(revision 2645)
@@ -0,0 +1,103 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+
+namespace SVM
+{
+    /// <summary>
+    /// Encapsulates a node in a Problem vector, with an index and a value (for more efficient representation
+    /// of sparse data.
+    /// </summary>
+	[Serializable]
+	public class Node : IComparable<Node>
+	{
+        internal int _index;
+        internal double _value;
+
+        /// <summary>
+        /// Default Constructor.
+        /// </summary>
+        public Node()
+        {
+        }
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="index">The index of the value.</param>
+        /// <param name="value">The value to store.</param>
+        public Node(int index, double value)
+        {
+            _index = index;
+            _value = value;
+        }
+
+        /// <summary>
+        /// Index of this Node.
+        /// </summary>
+        public int Index
+        {
+            get
+            {
+                return _index;
+            }
+            set
+            {
+                _index = value;
+            }
+        }
+        /// <summary>
+        /// Value at Index.
+        /// </summary>
+        public double Value
+        {
+            get
+            {
+                return _value;
+            }
+            set
+            {
+                _value = value;
+            }
+        }
+
+        /// <summary>
+        /// String representation of this Node as {index}:{value}.
+        /// </summary>
+        /// <returns>{index}:{value}</returns>
+        public override string ToString()
+        {
+            return string.Format("{0}:{1}", _index, _value);
+        }
+
+        #region IComparable<Node> Members
+
+        /// <summary>
+        /// Compares this node with another.
+        /// </summary>
+        /// <param name="other">The node to compare to</param>
+        /// <returns>A positive number if this node is greater, a negative number if it is less than, or 0 if equal</returns>
+        public int CompareTo(Node other)
+        {
+            return _index.CompareTo(other._index);
+        }
+
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Parameter.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Parameter.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Parameter.cs	(revision 2645)
@@ -0,0 +1,315 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace SVM
+{
+    /// <summary>
+    /// Contains all of the types of SVM this library can model.
+    /// </summary>
+    public enum SvmType { 
+        /// <summary>
+        /// C-SVC.
+        /// </summary>
+        C_SVC, 
+        /// <summary>
+        /// nu-SVC.
+        /// </summary>
+        NU_SVC, 
+        /// <summary>
+        /// one-class SVM
+        /// </summary>
+        ONE_CLASS, 
+        /// <summary>
+        /// epsilon-SVR
+        /// </summary>
+        EPSILON_SVR, 
+        /// <summary>
+        /// nu-SVR
+        /// </summary>
+        NU_SVR 
+    };
+    /// <summary>
+    /// Contains the various kernel types this library can use.
+    /// </summary>
+    public enum KernelType { 
+        /// <summary>
+        /// Linear: u'*v
+        /// </summary>
+        LINEAR, 
+        /// <summary>
+        /// Polynomial: (gamma*u'*v + coef0)^degree
+        /// </summary>
+        POLY, 
+        /// <summary>
+        /// Radial basis function: exp(-gamma*|u-v|^2)
+        /// </summary>
+        RBF, 
+        /// <summary>
+        /// Sigmoid: tanh(gamma*u'*v + coef0)
+        /// </summary>
+        SIGMOID,
+        /// <summary>
+        /// Precomputed kernel
+        /// </summary>
+        PRECOMPUTED,
+    };
+
+    /// <summary>
+    /// This class contains the various parameters which can affect the way in which an SVM
+    /// is learned.  Unless you know what you are doing, chances are you are best off using
+    /// the default values.
+    /// </summary>
+	[Serializable]
+	public class Parameter : ICloneable
+	{
+        private SvmType _svmType;
+        private KernelType _kernelType;
+        private int _degree;
+        private double _gamma;
+        private double _coef0;
+
+        private double _cacheSize;
+        private double _C;
+        private double _eps;
+
+        private Dictionary<int, double> _weights;
+        private double _nu;
+        private double _p;
+        private bool _shrinking;
+        private bool _probability;
+
+        /// <summary>
+        /// Default Constructor.  Gives good default values to all parameters.
+        /// </summary>
+        public Parameter()
+        {
+            _svmType = SvmType.C_SVC;
+            _kernelType = KernelType.RBF;
+            _degree = 3;
+            _gamma = 0; // 1/k
+            _coef0 = 0;
+            _nu = 0.5;
+            _cacheSize = 40;
+            _C = 1;
+            _eps = 1e-3;
+            _p = 0.1;
+            _shrinking = true;
+            _probability = false;
+            _weights = new Dictionary<int, double>();
+        }
+
+        /// <summary>
+        /// Type of SVM (default C-SVC)
+        /// </summary>
+        public SvmType SvmType
+        {
+            get
+            {
+                return _svmType;
+            }
+            set
+            {
+                _svmType = value;
+            }
+        }
+        /// <summary>
+        /// Type of kernel function (default Polynomial)
+        /// </summary>
+        public KernelType KernelType
+        {
+            get
+            {
+                return _kernelType;
+            }
+            set
+            {
+                _kernelType = value;
+            }
+        }
+        /// <summary>
+        /// Degree in kernel function (default 3).
+        /// </summary>
+        public int Degree
+        {
+            get
+            {
+                return _degree;
+            }
+            set
+            {
+                _degree = value;
+            }
+        }
+        /// <summary>
+        /// Gamma in kernel function (default 1/k)
+        /// </summary>
+        public double Gamma
+        {
+            get
+            {
+                return _gamma;
+            }
+            set
+            {
+                _gamma = value;
+            }
+        }
+        /// <summary>
+        /// Zeroeth coefficient in kernel function (default 0)
+        /// </summary>
+        public double Coefficient0
+        {
+            get
+            {
+                return _coef0;
+            }
+            set
+            {
+                _coef0 = value;
+            }
+        }
+		
+        /// <summary>
+        /// Cache memory size in MB (default 100)
+        /// </summary>
+        public double CacheSize
+        {
+            get
+            {
+                return _cacheSize;
+            }
+            set
+            {
+                _cacheSize = value;
+            }
+        }
+        /// <summary>
+        /// Tolerance of termination criterion (default 0.001)
+        /// </summary>
+        public double EPS
+        {
+            get
+            {
+                return _eps;
+            }
+            set
+            {
+                _eps = value;
+            }
+        }
+        /// <summary>
+        /// The parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)
+        /// </summary>
+        public double C
+        {
+            get
+            {
+                return _C;
+            }
+            set
+            {
+                _C = value;
+            }
+        }
+
+        /// <summary>
+        /// Contains custom weights for class labels.  Default weight value is 1.
+        /// </summary>
+        public Dictionary<int,double> Weights
+        {
+            get{
+                return _weights;
+            }
+        }
+
+        /// <summary>
+        /// The parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
+        /// </summary>
+        public double Nu
+        {
+            get
+            {
+                return _nu;
+            }
+            set
+            {
+                _nu = value;
+            }
+        }
+        /// <summary>
+        /// The epsilon in loss function of epsilon-SVR (default 0.1)
+        /// </summary>
+        public double P
+        {
+            get
+            {
+                return _p;
+            }
+            set
+            {
+                _p = value;
+            }
+        }
+        /// <summary>
+        /// Whether to use the shrinking heuristics, (default True)
+        /// </summary>
+        public bool Shrinking
+        {
+            get
+            {
+                return _shrinking;
+            }
+            set
+            {
+                _shrinking = value;
+            }
+        }
+        /// <summary>
+        /// Whether to train an SVC or SVR model for probability estimates, (default False)
+        /// </summary>
+        public bool Probability
+        {
+            get
+            {
+                return _probability;
+            }
+            set
+            {
+                _probability = value;
+            }
+        }
+
+
+        #region ICloneable Members
+        /// <summary>
+        /// Creates a memberwise clone of this parameters object.
+        /// </summary>
+        /// <returns>The clone (as type Parameter)</returns>
+        public object Clone()
+        {
+            return base.MemberwiseClone();
+        }
+
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/ParameterSelection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/ParameterSelection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/ParameterSelection.cs	(revision 2645)
@@ -0,0 +1,239 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace SVM
+{
+    /// <summary>
+    /// This class contains routines which perform parameter selection for a model which uses C-SVC and
+    /// an RBF kernel.
+    /// </summary>
+    public static class ParameterSelection
+    {
+        /// <summary>
+        /// Default number of times to divide the data.
+        /// </summary>
+        public const int NFOLD = 5;
+        /// <summary>
+        /// Default minimum power of 2 for the C value (-5)
+        /// </summary>
+        public const int MIN_C = -5;
+        /// <summary>
+        /// Default maximum power of 2 for the C value (15)
+        /// </summary>
+        public const int MAX_C = 15;
+        /// <summary>
+        /// Default power iteration step for the C value (2)
+        /// </summary>
+        public const int C_STEP = 2;
+        /// <summary>
+        /// Default minimum power of 2 for the Gamma value (-15)
+        /// </summary>
+        public const int MIN_G = -15;
+        /// <summary>
+        /// Default maximum power of 2 for the Gamma Value (3)
+        /// </summary>
+        public const int MAX_G = 3;
+        /// <summary>
+        /// Default power iteration step for the Gamma value (2)
+        /// </summary>
+        public const int G_STEP = 2;
+
+        /// <summary>
+        /// Returns a logarithmic list of values from minimum power of 2 to the maximum power of 2 using the provided iteration size.
+        /// </summary>
+        /// <param name="minPower">The minimum power of 2</param>
+        /// <param name="maxPower">The maximum power of 2</param>
+        /// <param name="iteration">The iteration size to use in powers</param>
+        /// <returns></returns>
+        public static List<double> GetList(double minPower, double maxPower, double iteration)
+        {
+            List<double> list = new List<double>();
+            for (double d = minPower; d <= maxPower; d += iteration)
+                list.Add(Math.Pow(2, d));
+            return list;
+        }
+
+        /// <summary>
+        /// Performs a Grid parameter selection, trying all possible combinations of the two lists and returning the
+        /// combination which performed best.  The default ranges of C and Gamma values are used.  Use this method if there is no validation data available, and it will
+        /// divide it 5 times to allow 5-fold validation (training on 4/5 and validating on 1/5, 5 times).
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="parameters">The parameters to use when optimizing</param>
+        /// <param name="outputFile">Output file for the parameter results.</param>
+        /// <param name="C">The optimal C value will be put into this variable</param>
+        /// <param name="Gamma">The optimal Gamma value will be put into this variable</param>
+        public static void Grid(
+            Problem problem,
+            Parameter parameters,
+            string outputFile,
+            out double C,
+            out double Gamma)
+        {
+            Grid(problem, parameters, GetList(MIN_C, MAX_C, C_STEP), GetList(MIN_G, MAX_G, G_STEP), outputFile, NFOLD, out C, out Gamma);
+        }
+        /// <summary>
+        /// Performs a Grid parameter selection, trying all possible combinations of the two lists and returning the
+        /// combination which performed best.  Use this method if there is no validation data available, and it will
+        /// divide it 5 times to allow 5-fold validation (training on 4/5 and validating on 1/5, 5 times).
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="parameters">The parameters to use when optimizing</param>
+        /// <param name="CValues">The set of C values to use</param>
+        /// <param name="GammaValues">The set of Gamma values to use</param>
+        /// <param name="outputFile">Output file for the parameter results.</param>
+        /// <param name="C">The optimal C value will be put into this variable</param>
+        /// <param name="Gamma">The optimal Gamma value will be put into this variable</param>
+        public static void Grid(
+            Problem problem,
+            Parameter parameters,
+            List<double> CValues,
+            List<double> GammaValues,
+            string outputFile,
+            out double C,
+            out double Gamma)
+        {
+            Grid(problem, parameters, CValues, GammaValues, outputFile, NFOLD, out C, out Gamma);
+        }
+        /// <summary>
+        /// Performs a Grid parameter selection, trying all possible combinations of the two lists and returning the
+        /// combination which performed best.  Use this method if validation data isn't available, as it will
+        /// divide the training data and train on a portion of it and test on the rest.
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="parameters">The parameters to use when optimizing</param>
+        /// <param name="CValues">The set of C values to use</param>
+        /// <param name="GammaValues">The set of Gamma values to use</param>
+        /// <param name="outputFile">Output file for the parameter results.</param>
+        /// <param name="nrfold">The number of times the data should be divided for validation</param>
+        /// <param name="C">The optimal C value will be placed in this variable</param>
+        /// <param name="Gamma">The optimal Gamma value will be placed in this variable</param>
+        public static void Grid(
+            Problem problem,
+            Parameter parameters,
+            List<double> CValues, 
+            List<double> GammaValues, 
+            string outputFile,
+            int nrfold,
+            out double C,
+            out double Gamma)
+        {
+            C = 0;
+            Gamma = 0;
+            double crossValidation = double.MinValue;
+            StreamWriter output = null;
+            if(outputFile != null)
+                output = new StreamWriter(outputFile);
+            for(int i=0; i<CValues.Count; i++)
+                for (int j = 0; j < GammaValues.Count; j++)
+                {
+                    parameters.C = CValues[i];
+                    parameters.Gamma = GammaValues[j];
+                    double test = Training.PerformCrossValidation(problem, parameters, nrfold);
+                    Console.Write("{0} {1} {2}", parameters.C, parameters.Gamma, test);
+                    if(output != null)
+                        output.WriteLine("{0} {1} {2}", parameters.C, parameters.Gamma, test);
+                    if (test > crossValidation)
+                    {
+                        C = parameters.C;
+                        Gamma = parameters.Gamma;
+                        crossValidation = test;
+                        Console.WriteLine(" New Maximum!");
+                    }
+                    else Console.WriteLine();
+                }
+            if(output != null)
+                output.Close();
+        }
+        /// <summary>
+        /// Performs a Grid parameter selection, trying all possible combinations of the two lists and returning the
+        /// combination which performed best.  Uses the default values of C and Gamma.
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="validation">The validation data</param>
+        /// <param name="parameters">The parameters to use when optimizing</param>
+        /// <param name="outputFile">The output file for the parameter results</param>
+        /// <param name="C">The optimal C value will be placed in this variable</param>
+        /// <param name="Gamma">The optimal Gamma value will be placed in this variable</param>
+        public static void Grid(
+            Problem problem,
+            Problem validation,
+            Parameter parameters,
+            string outputFile,
+            out double C,
+            out double Gamma)
+        {
+            Grid(problem, validation, parameters, GetList(MIN_C, MAX_C, C_STEP), GetList(MIN_G, MAX_G, G_STEP), outputFile, out C, out Gamma);
+        }
+        /// <summary>
+        /// Performs a Grid parameter selection, trying all possible combinations of the two lists and returning the
+        /// combination which performed best.
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="validation">The validation data</param>
+        /// <param name="parameters">The parameters to use when optimizing</param>
+        /// <param name="CValues">The C values to use</param>
+        /// <param name="GammaValues">The Gamma values to use</param>
+        /// <param name="outputFile">The output file for the parameter results</param>
+        /// <param name="C">The optimal C value will be placed in this variable</param>
+        /// <param name="Gamma">The optimal Gamma value will be placed in this variable</param>
+        public static void Grid(
+            Problem problem,
+            Problem validation,
+            Parameter parameters,
+            List<double> CValues,
+            List<double> GammaValues,
+            string outputFile,
+            out double C,
+            out double Gamma)
+        {
+            C = 0;
+            Gamma = 0;
+            double maxScore = double.MinValue;
+            StreamWriter output = null;
+            if(outputFile != null)
+                output = new StreamWriter(outputFile);
+            for (int i = 0; i < CValues.Count; i++)
+                for (int j = 0; j < GammaValues.Count; j++)
+                {
+                    parameters.C = CValues[i];
+                    parameters.Gamma = GammaValues[j];
+                    Model model = Training.Train(problem, parameters);
+                    double test = Prediction.Predict(validation, "tmp.txt", model, false);
+                    Console.Write("{0} {1} {2}", parameters.C, parameters.Gamma, test);
+                    if(output != null)
+                        output.WriteLine("{0} {1} {2}", parameters.C, parameters.Gamma, test);
+                    if (test > maxScore)
+                    {
+                        C = parameters.C;
+                        Gamma = parameters.Gamma;
+                        maxScore = test;
+                        Console.WriteLine(" New Maximum!");
+                    }
+                    else Console.WriteLine();
+                }
+            if(output != null)
+                output.Close();
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/PerformanceEvaluator.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/PerformanceEvaluator.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/PerformanceEvaluator.cs	(revision 2645)
@@ -0,0 +1,415 @@
+﻿/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Globalization;
+
+namespace SVM
+{
+    /// <summary>
+    /// Class encoding a member of a ranked set of labels.
+    /// </summary>
+    public class RankPair : IComparable<RankPair>
+    {
+        private double _score, _label;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="score">Score for this pair</param>
+        /// <param name="label">Label associated with the given score</param>
+        public RankPair(double score, double label)
+        {
+            _score = score;
+            _label = label;
+        }
+
+        /// <summary>
+        /// The score for this pair.
+        /// </summary>
+        public double Score
+        {
+            get
+            {
+                return _score;
+            }
+        }
+
+        /// <summary>
+        /// The Label for this pair.
+        /// </summary>
+        public double Label
+        {
+            get
+            {
+                return _label;
+            }
+        }
+
+        #region IComparable<RankPair> Members
+
+        /// <summary>
+        /// Compares this pair to another.  It will end up in a sorted list in decending score order.
+        /// </summary>
+        /// <param name="other">The pair to compare to</param>
+        /// <returns>Whether this should come before or after the argument</returns>
+        public int CompareTo(RankPair other)
+        {
+            return other.Score.CompareTo(Score);
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Returns a string representation of this pair.
+        /// </summary>
+        /// <returns>A string in the for Score:Label</returns>
+        public override string ToString()
+        {
+            return string.Format("{0}:{1}", Score, Label);
+        }
+    }
+
+    /// <summary>
+    /// Class encoding the point on a 2D curve.
+    /// </summary>
+    public class CurvePoint
+    {
+        private float _x, _y;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="x">X coordinate</param>
+        /// <param name="y">Y coordinate</param>
+        public CurvePoint(float x, float y)
+        {
+            _x = x;
+            _y = y;
+        }
+
+        /// <summary>
+        /// X coordinate
+        /// </summary>
+        public float X
+        {
+            get
+            {
+                return _x;
+            }
+        }
+
+        /// <summary>
+        /// Y coordinate
+        /// </summary>
+        public float Y
+        {
+            get
+            {
+                return _y;
+            }
+        }
+
+        /// <summary>
+        /// Creates a string representation of this point.
+        /// </summary>
+        /// <returns>string in the form (x, y)</returns>
+        public override string ToString()
+        {
+            return string.Format("({0}, {1})", _x, _y);
+        }
+    }
+
+    /// <summary>
+    /// Class which evaluates an SVM model using several standard techniques.
+    /// </summary>
+    public class PerformanceEvaluator
+    {
+        private class ChangePoint
+        {
+            public ChangePoint(int tp, int fp, int tn, int fn)
+            {
+                TP = tp;
+                FP = fp;
+                TN = tn;
+                FN = fn;
+            }
+
+            public int TP, FP, TN, FN;
+
+            public override string ToString()
+            {
+                return string.Format("{0}:{1}:{2}:{3}", TP, FP, TN, FN);
+            }
+        }
+
+        private List<CurvePoint> _prCurve;
+        private double _ap;
+
+        private List<CurvePoint> _rocCurve;
+        private double _auc;
+
+        private List<RankPair> _data;
+        private List<ChangePoint> _changes;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="set">A pre-computed ranked pair set</param>
+        public PerformanceEvaluator(List<RankPair> set)
+        {
+            _data = set;
+            computeStatistics();
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="model">Model to evaluate</param>
+        /// <param name="problem">Problem to evaluate</param>
+        /// <param name="category">Label to be evaluate for</param>
+        public PerformanceEvaluator(Model model, Problem problem, double category) : this(model, problem, category, "tmp.results") { }
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="model">Model to evaluate</param>
+        /// <param name="problem">Problem to evaluate</param>
+        /// <param name="resultsFile">Results file for output</param>
+        /// <param name="category">Category to evaluate for</param>
+        public PerformanceEvaluator(Model model, Problem problem, double category, string resultsFile)
+        {
+            Prediction.Predict(problem, resultsFile, model, true);
+            parseResultsFile(resultsFile, problem.Y, category);
+
+            computeStatistics();
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="resultsFile">Results file</param>
+        /// <param name="correctLabels">The correct labels of each data item</param>
+        /// <param name="category">The category to evaluate for</param>
+        public PerformanceEvaluator(string resultsFile, double[] correctLabels, double category)
+        {
+            parseResultsFile(resultsFile, correctLabels, category);
+            computeStatistics();
+        }
+
+        private void parseResultsFile(string resultsFile, double[] labels, double category)
+        {
+            StreamReader input = new StreamReader(resultsFile);
+            string[] parts = input.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+            int confidenceIndex = -1;
+            for (int i = 1; i < parts.Length; i++)
+                if (double.Parse(parts[i], CultureInfo.InvariantCulture) == category)
+                {
+                    confidenceIndex = i;
+                    break;
+                }
+            _data = new List<RankPair>();
+            for (int i = 0; i < labels.Length; i++)
+            {
+                parts = input.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+                double confidence = double.Parse(parts[confidenceIndex], CultureInfo.InvariantCulture);
+                _data.Add(new RankPair(confidence, labels[i] == category ? 1 : 0));
+            }
+            input.Close();
+        }
+
+        private void computeStatistics()
+        {
+            _data.Sort();
+
+            findChanges();
+            computePR();
+            computeRoC();
+        }
+
+        private void findChanges()
+        {
+            int tp, fp, tn, fn;
+            tp = fp = tn = fn = 0;
+            for (int i = 0; i < _data.Count; i++)
+            {
+                if (_data[i].Label == 1)
+                    fn++;
+                else tn++;
+            }
+            _changes = new List<ChangePoint>();
+            for (int i = 0; i < _data.Count; i++)
+            {
+                if (_data[i].Label == 1)
+                {
+                    tp++;
+                    fn--;
+                }
+                else
+                {
+                    fp++;
+                    tn--;
+                }
+                _changes.Add(new ChangePoint(tp, fp, tn, fn));
+            }
+        }
+
+        private float computePrecision(ChangePoint p)
+        {
+            return (float)p.TP / (p.TP + p.FP);
+        }
+
+        private float computeRecall(ChangePoint p)
+        {
+            return (float)p.TP / (p.TP + p.FN);
+        }
+
+        private void computePR()
+        {
+            _prCurve = new List<CurvePoint>();
+            _prCurve.Add(new CurvePoint(0, 1));
+            float precision = computePrecision(_changes[0]);
+            float recall = computeRecall(_changes[0]);
+            float precisionSum = 0;
+            if (_changes[0].TP > 0)
+            {
+                precisionSum += precision;
+                _prCurve.Add(new CurvePoint(recall, precision));
+            }
+            for (int i = 1; i < _changes.Count; i++)
+            {
+                precision = computePrecision(_changes[i]);
+                recall = computeRecall(_changes[i]);
+                if (_changes[i].TP > _changes[i - 1].TP)
+                {
+                    precisionSum += precision;
+                    _prCurve.Add(new CurvePoint(recall, precision));
+                }
+            }
+            _prCurve.Add(new CurvePoint(1, (float)(_changes[0].TP + _changes[0].FN) / (_changes[0].FP + _changes[0].TN)));
+            _ap = precisionSum / (_changes[0].FN + _changes[0].TP);
+        }
+
+        /// <summary>
+        /// Writes the Precision-Recall curve to a tab-delimited file.
+        /// </summary>
+        /// <param name="filename">Filename for output</param>
+        public void WritePRCurve(string filename)
+        {
+            StreamWriter output = new StreamWriter(filename);
+            output.WriteLine(_ap);
+            for (int i = 0; i < _prCurve.Count; i++)
+                output.WriteLine("{0}\t{1}", _prCurve[i].X, _prCurve[i].Y);
+            output.Close();
+        }
+
+        /// <summary>
+        /// Writes the Receiver Operating Characteristic curve to a tab-delimited file.
+        /// </summary>
+        /// <param name="filename">Filename for output</param>
+        public void WriteROCCurve(string filename)
+        {
+            StreamWriter output = new StreamWriter(filename);
+            output.WriteLine(_auc);
+            for (int i = 0; i < _rocCurve.Count; i++)
+                output.WriteLine("{0}\t{1}", _rocCurve[i].X, _rocCurve[i].Y);
+            output.Close();
+        }
+
+        /// <summary>
+        /// Receiver Operating Characteristic curve
+        /// </summary>
+        public List<CurvePoint> ROCCurve
+        {
+            get
+            {
+                return _rocCurve;
+            }
+        }
+
+        /// <summary>
+        /// Returns the area under the ROC Curve
+        /// </summary>
+        public double AuC
+        {
+            get
+            {
+                return _auc;
+            }
+        }
+
+        /// <summary>
+        /// Precision-Recall curve
+        /// </summary>
+        public List<CurvePoint> PRCurve
+        {
+            get
+            {
+                return _prCurve;
+            }
+        }
+
+        /// <summary>
+        /// The average precision
+        /// </summary>
+        public double AP
+        {
+            get
+            {
+                return _ap;
+            }
+        }
+
+        private float computeTPR(ChangePoint cp)
+        {
+            return computeRecall(cp);
+        }
+
+        private float computeFPR(ChangePoint cp)
+        {
+            return (float)cp.FP / (cp.FP + cp.TN);
+        }
+
+        private void computeRoC()
+        {
+            _rocCurve = new List<CurvePoint>();
+            _rocCurve.Add(new CurvePoint(0, 0));
+            float tpr = computeTPR(_changes[0]);
+            float fpr = computeFPR(_changes[0]);
+            _rocCurve.Add(new CurvePoint(fpr, tpr));
+            _auc = 0;
+            for (int i = 1; i < _changes.Count; i++)
+            {
+                float newTPR = computeTPR(_changes[i]);
+                float newFPR = computeFPR(_changes[i]);
+                if (_changes[i].TP > _changes[i - 1].TP)
+                {
+                    _auc += tpr * (newFPR - fpr) + .5 * (newTPR - tpr) * (newFPR - fpr);
+                    tpr = newTPR;
+                    fpr = newFPR;
+                    _rocCurve.Add(new CurvePoint(fpr, tpr));
+                }
+            }
+            _rocCurve.Add(new CurvePoint(1, 1));
+            _auc += tpr * (1 - fpr) + .5 * (1 - tpr) * (1 - fpr);
+        }
+
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/PrecomputedKernel.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/PrecomputedKernel.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/PrecomputedKernel.cs	(revision 2645)
@@ -0,0 +1,117 @@
+﻿/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Collections.Generic;
+
+namespace SVM
+{
+    /// <summary>
+    /// Class encapsulating a precomputed kernel, where each position indicates the similarity score for two items in the training data.
+    /// </summary>
+    [Serializable]
+    public class PrecomputedKernel
+    {
+        private float[,] _similarities;
+        private int _rows;
+        private int _columns;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="similarities">The similarity scores between all items in the training data</param>
+        public PrecomputedKernel(float[,] similarities)
+        {
+            _similarities = similarities;
+            _rows = _similarities.GetLength(0);
+            _columns = _similarities.GetLength(1);
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="nodes">Nodes for self-similarity analysis</param>
+        /// <param name="param">Parameters to use when computing similarities</param>
+        public PrecomputedKernel(List<Node[]> nodes, Parameter param)
+        {
+            _rows = nodes.Count;
+            _columns = _rows;
+            _similarities = new float[_rows, _columns];
+            for (int r = 0; r < _rows; r++)
+            {
+                for (int c = 0; c < r; c++)
+                    _similarities[r, c] = _similarities[c, r];
+                _similarities[r, r] = 1;
+                for (int c = r + 1; c < _columns; c++)
+                    _similarities[r, c] = (float)Kernel.KernelFunction(nodes[r], nodes[c], param);
+            }
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="rows">Nodes to use as the rows of the matrix</param>
+        /// <param name="columns">Nodes to use as the columns of the matrix</param>
+        /// <param name="param">Parameters to use when compute similarities</param>
+        public PrecomputedKernel(List<Node[]> rows, List<Node[]> columns, Parameter param)
+        {
+            _rows = rows.Count;
+            _columns = columns.Count;
+            _similarities = new float[_rows, _columns];
+            for (int r = 0; r < _rows; r++)
+                for (int c = 0; c < _columns; c++)
+                    _similarities[r, c] = (float)Kernel.KernelFunction(rows[r], columns[c], param);
+        }
+
+        /// <summary>
+        /// Constructs a <see cref="Problem"/> object using the labels provided.  If a label is set to "0" that item is ignored.
+        /// </summary>
+        /// <param name="rowLabels">The labels for the row items</param>
+        /// <param name="columnLabels">The labels for the column items</param>
+        /// <returns>A <see cref="Problem"/> object</returns>
+        public Problem Compute(double[] rowLabels, double[] columnLabels)
+        {
+            List<Node[]> X = new List<Node[]>();
+            List<double> Y = new List<double>();
+            int maxIndex = 0;
+            for (int i = 0; i < columnLabels.Length; i++)
+                if (columnLabels[i] != 0)
+                    maxIndex++;
+            maxIndex++;
+            for (int r = 0; r < _rows; r++)
+            {
+                if (rowLabels[r] == 0)
+                    continue;
+                List<Node> nodes = new List<Node>();
+                nodes.Add(new Node(0, X.Count + 1));
+                for (int c = 0; c < _columns; c++)
+                {
+                    if (columnLabels[c] == 0)
+                        continue;
+                    double value = _similarities[r, c];
+                    nodes.Add(new Node(nodes.Count, value));
+                }
+                X.Add(nodes.ToArray());
+                Y.Add(rowLabels[r]);
+            }
+            return new Problem(X.Count, Y.ToArray(), X.ToArray(), maxIndex);
+        }
+
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Prediction.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Prediction.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Prediction.cs	(revision 2645)
@@ -0,0 +1,188 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.IO;
+using System.Diagnostics;
+
+namespace SVM
+{
+    /// <summary>
+    /// Class containing the routines to perform class membership prediction using a trained SVM.
+    /// </summary>
+    public static class Prediction
+    {
+        /// <summary>
+        /// Predicts the class memberships of all the vectors in the problem.
+        /// </summary>
+        /// <param name="problem">The SVM Problem to solve</param>
+        /// <param name="outputFile">File for result output</param>
+        /// <param name="model">The Model to use</param>
+        /// <param name="predict_probability">Whether to output a distribution over the classes</param>
+        /// <returns>Percentage correctly labelled</returns>
+        public static double Predict(
+            Problem problem,
+            string outputFile,
+            Model model,
+            bool predict_probability)
+        {
+            int correct = 0;
+            int total = 0;
+            double error = 0;
+            double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
+            StreamWriter output = outputFile != null ? new StreamWriter(outputFile) : null;
+
+            SvmType svm_type = Procedures.svm_get_svm_type(model);
+            int nr_class = Procedures.svm_get_nr_class(model);
+            int[] labels = new int[nr_class];
+            double[] prob_estimates = null;
+
+            if (predict_probability)
+            {
+                if (svm_type == SvmType.EPSILON_SVR || svm_type == SvmType.NU_SVR)
+                {
+                    Console.WriteLine("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + Procedures.svm_get_svr_probability(model));
+                }
+                else
+                {
+                    Procedures.svm_get_labels(model, labels);
+                    prob_estimates = new double[nr_class];
+                    if (output != null)
+                    {
+                        output.Write("labels");
+                        for (int j = 0; j < nr_class; j++)
+                        {
+                            output.Write(" " + labels[j]);
+                        }
+                        output.Write("\n");
+                    }
+                }
+            }
+            for (int i = 0; i < problem.Count; i++)
+            {
+                double target = problem.Y[i];
+                Node[] x = problem.X[i];
+
+                double v;
+                if (predict_probability && (svm_type == SvmType.C_SVC || svm_type == SvmType.NU_SVC))
+                {
+                    v = Procedures.svm_predict_probability(model, x, prob_estimates);
+                    if (output != null)
+                    {
+                        output.Write(v + " ");
+                        for (int j = 0; j < nr_class; j++)
+                        {
+                            output.Write(prob_estimates[j] + " ");
+                        }
+                        output.Write("\n");
+                    }
+                }
+                else
+                {
+                    v = Procedures.svm_predict(model, x);
+                    if(output != null)
+                        output.Write(v + "\n");
+                }
+
+                if (v == target)
+                    ++correct;
+                error += (v - target) * (v - target);
+                sumv += v;
+                sumy += target;
+                sumvv += v * v;
+                sumyy += target * target;
+                sumvy += v * target;
+                ++total;
+            }
+            if(output != null)
+                output.Close();
+            return (double)correct / total;
+        }
+
+        /// <summary>
+        /// Predict the class for a single input vector.
+        /// </summary>
+        /// <param name="model">The Model to use for prediction</param>
+        /// <param name="x">The vector for which to predict class</param>
+        /// <returns>The result</returns>
+        public static double Predict(Model model, Node[] x)
+        {
+            return Procedures.svm_predict(model, x);
+        }
+
+        /// <summary>
+        /// Predicts a class distribution for the single input vector.
+        /// </summary>
+        /// <param name="model">Model to use for prediction</param>
+        /// <param name="x">The vector for which to predict the class distribution</param>
+        /// <returns>A probability distribtion over classes</returns>
+        public static double[] PredictProbability(Model model, Node[] x)
+        {
+            SvmType svm_type = Procedures.svm_get_svm_type(model);
+            if (svm_type != SvmType.C_SVC && svm_type != SvmType.NU_SVC)
+                throw new Exception("Model type " + svm_type + " unable to predict probabilities.");
+            int nr_class = Procedures.svm_get_nr_class(model);
+            double[] probEstimates = new double[nr_class];
+            Procedures.svm_predict_probability(model, x, probEstimates);
+            return probEstimates;
+        }
+
+        private static void exit_with_help()
+        {
+            Debug.Write("usage: svm_predict [options] test_file model_file output_file\n" + "options:\n" + "-b probability_estimates: whether to predict probability estimates, 0 or 1 (default 0); one-class SVM not supported yet\n");
+            Environment.Exit(1);
+        }
+
+        /// <summary>
+        /// Legacy method, provided to allow usage as though this were the command line version of libsvm.
+        /// </summary>
+        /// <param name="args">Standard arguments passed to the svm_predict exectutable.  See libsvm documentation for details.</param>
+        [Obsolete("Use the other version of Predict() instead")]
+        public static void Predict(params string[] args)
+        {
+            int i = 0;
+            bool predictProbability = false;
+
+            // parse options
+            for (i = 0; i < args.Length; i++)
+            {
+                if (args[i][0] != '-')
+                    break;
+                ++i;
+                switch (args[i - 1][1])
+                {
+
+                    case 'b':
+                        predictProbability = int.Parse(args[i]) == 1;
+                        break;
+
+                    default:
+                        throw new ArgumentException("Unknown option");
+
+                }
+            }
+            if (i >= args.Length)
+                throw new ArgumentException("No input, model and output files provided");
+
+            Problem problem = Problem.Read(args[i]);
+            Model model = Model.Read(args[i + 1]);
+            Predict(problem, args[i + 2], model, predictProbability);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Problem.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Problem.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Problem.cs	(revision 2645)
@@ -0,0 +1,212 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Threading;
+using System.Globalization;
+
+namespace SVM
+{
+    /// <summary>
+    /// Encapsulates a problem, or set of vectors which must be classified.
+    /// </summary>
+	[Serializable]
+	public class Problem
+	{
+        private int _count;
+        private double[] _Y;
+        private Node[][] _X;
+        private int _maxIndex;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="count">Number of vectors</param>
+        /// <param name="y">The class labels</param>
+        /// <param name="x">Vector data.</param>
+        /// <param name="maxIndex">Maximum index for a vector</param>
+        public Problem(int count, double[] y, Node[][] x, int maxIndex)
+        {
+            _count = count;
+            _Y = y;
+            _X = x;
+            _maxIndex = maxIndex;
+        }
+        /// <summary>
+        /// Empty Constructor.  Nothing is initialized.
+        /// </summary>
+        public Problem()
+        {
+        }
+        /// <summary>
+        /// Number of vectors.
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                return _count;
+            }
+            set
+            {
+                _count = value;
+            }
+        }
+        /// <summary>
+        /// Class labels.
+        /// </summary>
+        public double[] Y
+        {
+            get
+            {
+                return _Y;
+            }
+            set
+            {
+                _Y = value;
+            }
+        }
+        /// <summary>
+        /// Vector data.
+        /// </summary>
+        public Node[][] X
+        {
+            get
+            {
+                return _X;
+            }
+            set
+            {
+                _X = value;
+            }
+        }
+        /// <summary>
+        /// Maximum index for a vector.
+        /// </summary>
+        public int MaxIndex
+        {
+            get
+            {
+                return _maxIndex;
+            }
+            set
+            {
+                _maxIndex = value;
+            }
+        }
+
+        /// <summary>
+        /// Reads a problem from a stream.
+        /// </summary>
+        /// <param name="stream">Stream to read from</param>
+        /// <returns>The problem</returns>
+        public static Problem Read(Stream stream)
+        {
+            TemporaryCulture.Start();
+
+            StreamReader input = new StreamReader(stream);
+            List<double> vy = new List<double>();
+            List<Node[]> vx = new List<Node[]>();
+            int max_index = 0;
+
+            while (input.Peek() > -1)
+            {
+                string[] parts = input.ReadLine().Trim().Split();
+
+                vy.Add(double.Parse(parts[0]));
+                int m = parts.Length - 1;
+                Node[] x = new Node[m];
+                for (int j = 0; j < m; j++)
+                {
+                    x[j] = new Node();
+                    string[] nodeParts = parts[j + 1].Split(':');
+                    x[j].Index = int.Parse(nodeParts[0]);
+                    x[j].Value = double.Parse(nodeParts[1]);
+                }
+                if (m > 0)
+                    max_index = Math.Max(max_index, x[m - 1].Index);
+                vx.Add(x);
+            }
+
+            TemporaryCulture.Stop();
+
+            return new Problem(vy.Count, vy.ToArray(), vx.ToArray(), max_index);
+        }
+
+        /// <summary>
+        /// Writes a problem to a stream.
+        /// </summary>
+        /// <param name="stream">The stream to write the problem to.</param>
+        /// <param name="problem">The problem to write.</param>
+        public static void Write(Stream stream, Problem problem)
+        {
+            TemporaryCulture.Start();
+
+            StreamWriter output = new StreamWriter(stream);
+            for (int i = 0; i < problem.Count; i++)
+            {
+                output.Write(problem.Y[i]);
+                for (int j = 0; j < problem.X[i].Length; j++)
+                    output.Write(" {0}:{1}", problem.X[i][j].Index, problem.X[i][j].Value);
+                output.WriteLine();
+            }
+            output.Flush();
+
+            TemporaryCulture.Stop();
+        }
+
+        /// <summary>
+        /// Reads a Problem from a file.
+        /// </summary>
+        /// <param name="filename">The file to read from.</param>
+        /// <returns>the Probem</returns>
+        public static Problem Read(string filename)
+        {
+            FileStream input = File.OpenRead(filename);
+            try
+            {
+                return Read(input);
+            }
+            finally
+            {
+                input.Close();
+            }
+        }
+
+        /// <summary>
+        /// Writes a problem to a file.   This will overwrite any previous data in the file.
+        /// </summary>
+        /// <param name="filename">The file to write to</param>
+        /// <param name="problem">The problem to write</param>
+        public static void Write(string filename, Problem problem)
+        {
+            FileStream output = File.Open(filename, FileMode.Create);
+            try
+            {
+                Write(output, problem);
+            }
+            finally
+            {
+                output.Close();
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Properties/AssemblyInfo.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Properties/AssemblyInfo.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Properties/AssemblyInfo.cs	(revision 2645)
@@ -0,0 +1,35 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("SVM.NET")]
+[assembly: AssemblyDescription("A .NET Support Vector Machine library adapted from libsvm")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Matthew Johnson")]
+[assembly: AssemblyProduct("SVM.NET")]
+[assembly: AssemblyCopyright("Copyright ©  Matthew Johnson 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("803d4e74-70db-432e-a4da-32e7a021eec2")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.6.3")]
+[assembly: AssemblyFileVersion("1.6.3")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/RangeTransform.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/RangeTransform.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/RangeTransform.cs	(revision 2645)
@@ -0,0 +1,225 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Globalization;
+
+namespace SVM {
+  /// <summary>
+  /// Class which encapsulates a range transformation.
+  /// </summary>
+  public class RangeTransform : IRangeTransform {
+    /// <summary>
+    /// Default lower bound for scaling (-1).
+    /// </summary>
+    public const int DEFAULT_LOWER_BOUND = -1;
+    /// <summary>
+    /// Default upper bound for scaling (1).
+    /// </summary>
+    public const int DEFAULT_UPPER_BOUND = 1;
+
+    /// <summary>
+    /// Determines the Range transform for the provided problem.  Uses the default lower and upper bounds.
+    /// </summary>
+    /// <param name="prob">The Problem to analyze</param>
+    /// <returns>The Range transform for the problem</returns>
+    public static RangeTransform Compute(Problem prob) {
+      return Compute(prob, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
+    }
+    /// <summary>
+    /// Determines the Range transform for the provided problem.
+    /// </summary>
+    /// <param name="prob">The Problem to analyze</param>
+    /// <param name="lowerBound">The lower bound for scaling</param>
+    /// <param name="upperBound">The upper bound for scaling</param>
+    /// <returns>The Range transform for the problem</returns>
+    public static RangeTransform Compute(Problem prob, double lowerBound, double upperBound) {
+      double[] minVals = new double[prob.MaxIndex];
+      double[] maxVals = new double[prob.MaxIndex];
+      for (int i = 0; i < prob.MaxIndex; i++) {
+        minVals[i] = double.MaxValue;
+        maxVals[i] = double.MinValue;
+      }
+      for (int i = 0; i < prob.Count; i++) {
+        for (int j = 0; j < prob.X[i].Length; j++) {
+          int index = prob.X[i][j].Index - 1;
+          double value = prob.X[i][j].Value;
+          minVals[index] = Math.Min(minVals[index], value);
+          maxVals[index] = Math.Max(maxVals[index], value);
+        }
+      }
+      for (int i = 0; i < prob.MaxIndex; i++) {
+        if (minVals[i] == double.MaxValue || maxVals[i] == double.MinValue) {
+          minVals[i] = 0;
+          maxVals[i] = 0;
+        }
+      }
+      return new RangeTransform(minVals, maxVals, lowerBound, upperBound);
+    }
+
+    private double[] _inputStart;
+    private double[] _inputScale;
+    private double _outputStart;
+    private double _outputScale;
+    private int _length;
+
+    /// <summary>
+    /// Constructor.
+    /// </summary>
+    /// <param name="minValues">The minimum values in each dimension.</param>
+    /// <param name="maxValues">The maximum values in each dimension.</param>
+    /// <param name="lowerBound">The desired lower bound for all dimensions.</param>
+    /// <param name="upperBound">The desired upper bound for all dimensions.</param>
+    public RangeTransform(double[] minValues, double[] maxValues, double lowerBound, double upperBound) {
+      _length = minValues.Length;
+      if (maxValues.Length != _length)
+        throw new Exception("Number of max and min values must be equal.");
+      _inputStart = new double[_length];
+      _inputScale = new double[_length];
+      for (int i = 0; i < _length; i++) {
+        _inputStart[i] = minValues[i];
+        _inputScale[i] = maxValues[i] - minValues[i];
+      }
+      _outputStart = lowerBound;
+      _outputScale = upperBound - lowerBound;
+    }
+    private RangeTransform(double[] inputStart, double[] inputScale, double outputStart, double outputScale, int length) {
+      _inputStart = inputStart;
+      _inputScale = inputScale;
+      _outputStart = outputStart;
+      _outputScale = outputScale;
+      _length = length;
+    }
+    /// <summary>
+    /// Transforms the input array based upon the values provided.
+    /// </summary>
+    /// <param name="input">The input array</param>
+    /// <returns>A scaled array</returns>
+    public Node[] Transform(Node[] input) {
+      Node[] output = new Node[input.Length];
+      for (int i = 0; i < output.Length; i++) {
+        int index = input[i].Index;
+        double value = input[i].Value;
+        output[i] = new Node(index, Transform(value, index));
+      }
+      return output;
+    }
+
+    /// <summary>
+    /// Transforms this an input value using the scaling transform for the provided dimension.
+    /// </summary>
+    /// <param name="input">The input value to transform</param>
+    /// <param name="index">The dimension whose scaling transform should be used</param>
+    /// <returns>The scaled value</returns>
+    public double Transform(double input, int index) {
+      index--;
+      double tmp = input - _inputStart[index];
+      if (_inputScale[index] == 0)
+        return 0;
+      tmp /= _inputScale[index];
+      tmp *= _outputScale;
+      return tmp + _outputStart;
+    }
+    /// <summary>
+    /// Writes this Range transform to a stream.
+    /// </summary>
+    /// <param name="stream">The stream to write to</param>
+    /// <param name="r">The range to write</param>
+    public static void Write(Stream stream, RangeTransform r) {
+      TemporaryCulture.Start();
+
+      StreamWriter output = new StreamWriter(stream);
+      output.WriteLine(r._length);
+      output.Write(r._inputStart[0].ToString("r"));
+      for (int i = 1; i < r._inputStart.Length; i++)
+        output.Write(" " + r._inputStart[i].ToString("r"));
+      output.WriteLine();
+      output.Write(r._inputScale[0].ToString("r"));
+      for (int i = 1; i < r._inputScale.Length; i++)
+        output.Write(" " + r._inputScale[i].ToString("r"));
+      output.WriteLine();
+      output.WriteLine("{0} {1}", r._outputStart.ToString("r"), r._outputScale.ToString("r"));
+      output.Flush();
+
+      TemporaryCulture.Stop();
+    }
+
+    /// <summary>
+    /// Writes this Range transform to a file.    This will overwrite any previous data in the file.
+    /// </summary>
+    /// <param name="outputFile">The file to write to</param>
+    /// <param name="r">The Range to write</param>
+    public static void Write(string outputFile, RangeTransform r) {
+      FileStream s = File.Open(outputFile, FileMode.Create);
+      try {
+        Write(s, r);
+      }
+      finally {
+        s.Close();
+      }
+    }
+
+    /// <summary>
+    /// Reads a Range transform from a file.
+    /// </summary>
+    /// <param name="inputFile">The file to read from</param>
+    /// <returns>The Range transform</returns>
+    public static RangeTransform Read(string inputFile) {
+      FileStream s = File.OpenRead(inputFile);
+      try {
+        return Read(s);
+      }
+      finally {
+        s.Close();
+      }
+    }
+
+    /// <summary>
+    /// Reads a Range transform from a stream.
+    /// </summary>
+    /// <param name="stream">The stream to read from</param>
+    /// <returns>The Range transform</returns>
+    public static RangeTransform Read(Stream stream) {
+      return Read(new StreamReader(stream));
+    }
+
+    public static RangeTransform Read(TextReader input) {
+      TemporaryCulture.Start();
+
+      int length = int.Parse(input.ReadLine());
+      double[] inputStart = new double[length];
+      double[] inputScale = new double[length];
+      string[] parts = input.ReadLine().Split();
+      for (int i = 0; i < length; i++)
+        inputStart[i] = double.Parse(parts[i]);
+      parts = input.ReadLine().Split();
+      for (int i = 0; i < length; i++)
+        inputScale[i] = double.Parse(parts[i]);
+      parts = input.ReadLine().Split();
+      double outputStart = double.Parse(parts[0]);
+      double outputScale = double.Parse(parts[1]);
+
+      TemporaryCulture.Stop();
+
+      return new RangeTransform(inputStart, inputScale, outputStart, outputScale, length);
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/SVMExtensions.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/SVMExtensions.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/SVMExtensions.cs	(revision 2645)
@@ -0,0 +1,17 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SVM
+{
+    internal static class SVMExtensions
+    {
+        public static void SwapIndex<T>(this T[] list, int i, int j)
+        {
+            T tmp = list[i];
+            list[i] = list[j];
+            list[j] = tmp;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Scaling.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Scaling.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Scaling.cs	(revision 2645)
@@ -0,0 +1,49 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+
+namespace SVM
+{
+    /// <summary>
+    /// Deals with the scaling of Problems so they have uniform ranges across all dimensions in order to
+    /// result in better SVM performance.
+    /// </summary>
+    public static class Scaling
+    {
+        /// <summary>
+        /// Scales a problem using the provided range.  This will not affect the parameter.
+        /// </summary>
+        /// <param name="prob">The problem to scale</param>
+        /// <param name="range">The Range transform to use in scaling</param>
+        /// <returns>The Scaled problem</returns>
+        public static Problem Scale(this IRangeTransform range, Problem prob)
+        {
+            Problem scaledProblem = new Problem(prob.Count, new double[prob.Count], new Node[prob.Count][], prob.MaxIndex);
+            for (int i = 0; i < scaledProblem.Count; i++)
+            {
+                scaledProblem.X[i] = new Node[prob.X[i].Length];
+                for (int j = 0; j < scaledProblem.X[i].Length; j++)
+                    scaledProblem.X[i][j] = new Node(prob.X[i][j].Index, range.Transform(prob.X[i][j].Value, prob.X[i][j].Index));
+                scaledProblem.Y[i] = prob.Y[i];
+            }
+            return scaledProblem;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Solver.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Solver.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Solver.cs	(revision 2645)
@@ -0,0 +1,2245 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+
+namespace SVM
+{
+
+    // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918
+    // Solves:
+    //
+    //	Min 0.5(\alpha^T Q \alpha) + p^T \alpha
+    //
+    //		y^T \alpha = \delta
+    //		y_i = +1 or -1
+    //		0 <= alpha_i <= Cp for y_i = 1
+    //		0 <= alpha_i <= Cn for y_i = -1
+    //
+    // Given:
+    //
+    //	Q, p, y, Cp, Cn, and an initial feasible point \alpha
+    //	l is the size of vectors and matrices
+    //	eps is the stopping tolerance
+    //
+    // solution will be put in \alpha, objective value will be put in obj
+    //
+    internal class Solver
+    {
+        protected int active_size;
+        protected sbyte[] y;
+        protected double[] G;		// gradient of objective function
+        private const byte LOWER_BOUND = 0;
+        private const byte UPPER_BOUND = 1;
+        private const byte FREE = 2;
+        private byte[] alpha_status;	// LOWER_BOUND, UPPER_BOUND, FREE
+        private double[] alpha;
+        protected IQMatrix Q;
+        protected float[] QD;
+        protected double EPS;
+        private double Cp, Cn;
+        private double[] p;
+        private int[] active_set;
+        private double[] G_bar;		// gradient, if we treat free variables as 0
+        protected int l;
+        protected bool unshrink;	// XXX
+
+        protected const double INF = double.PositiveInfinity;
+
+        private double get_C(int i)
+        {
+            return (y[i] > 0) ? Cp : Cn;
+        }
+
+        private void update_alpha_status(int i)
+        {
+            if (alpha[i] >= get_C(i))
+                alpha_status[i] = UPPER_BOUND;
+            else if (alpha[i] <= 0)
+                alpha_status[i] = LOWER_BOUND;
+            else alpha_status[i] = FREE;
+        }
+
+        protected bool is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; }
+        protected bool is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; }
+
+        private bool is_free(int i) { return alpha_status[i] == FREE; }
+
+        public class SolutionInfo
+        {
+            public double obj;
+            public double rho;
+            public double upper_bound_p;
+            public double upper_bound_n;
+            public double r;	// for Solver_NU
+        }
+
+        protected void swap_index(int i, int j)
+        {
+            Q.SwapIndex(i, j);
+            y.SwapIndex(i, j);
+            G.SwapIndex(i, j);
+            alpha_status.SwapIndex(i, j);
+            alpha.SwapIndex(i, j);
+            p.SwapIndex(i, j);
+            active_set.SwapIndex(i, j);
+            G_bar.SwapIndex(i, j);
+        }
+
+        protected void reconstruct_gradient()
+        {
+            // reconstruct inactive elements of G from G_bar and free variables
+
+            if (active_size == l) return;
+
+            int i, j;
+            int nr_free = 0;
+
+            for (j = active_size; j < l; j++)
+                G[j] = G_bar[j] + p[j];
+
+            for (j = 0; j < active_size; j++)
+                if (is_free(j))
+                    nr_free++;
+
+            if (2 * nr_free < active_size)
+                Procedures.info("\nWarning: using -h 0 may be faster\n");
+
+            if (nr_free * l > 2 * active_size * (l - active_size))
+            {
+                for (i = active_size; i < l; i++)
+                {
+                    float[] Q_i = Q.GetQ(i, active_size);
+                    for (j = 0; j < active_size; j++)
+                        if (is_free(j))
+                            G[i] += alpha[j] * Q_i[j];
+                }
+            }
+            else
+            {
+                for (i = 0; i < active_size; i++)
+                    if (is_free(i))
+                    {
+                        float[] Q_i = Q.GetQ(i, l);
+                        double alpha_i = alpha[i];
+                        for (j = active_size; j < l; j++)
+                            G[j] += alpha_i * Q_i[j];
+                    }
+            }
+        }
+
+        public virtual void Solve(int l, IQMatrix Q, double[] p_, sbyte[] y_, double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, bool shrinking)
+        {
+            this.l = l;
+            this.Q = Q;
+            QD = Q.GetQD();
+            p = (double[])p_.Clone();
+            y = (sbyte[])y_.Clone();
+            alpha = (double[])alpha_.Clone();
+            this.Cp = Cp;
+            this.Cn = Cn;
+            this.EPS = eps;
+            this.unshrink = false;
+
+            // initialize alpha_status
+            {
+                alpha_status = new byte[l];
+                for (int i = 0; i < l; i++)
+                    update_alpha_status(i);
+            }
+
+            // initialize active set (for shrinking)
+            {
+                active_set = new int[l];
+                for (int i = 0; i < l; i++)
+                    active_set[i] = i;
+                active_size = l;
+            }
+
+            // initialize gradient
+            {
+                G = new double[l];
+                G_bar = new double[l];
+                int i;
+                for (i = 0; i < l; i++)
+                {
+                    G[i] = p[i];
+                    G_bar[i] = 0;
+                }
+                for (i = 0; i < l; i++)
+                    if (!is_lower_bound(i))
+                    {
+                        float[] Q_i = Q.GetQ(i, l);
+                        double alpha_i = alpha[i];
+                        int j;
+                        for (j = 0; j < l; j++)
+                            G[j] += alpha_i * Q_i[j];
+                        if (is_upper_bound(i))
+                            for (j = 0; j < l; j++)
+                                G_bar[j] += get_C(i) * Q_i[j];
+                    }
+            }
+
+            // optimization step
+
+            int iter = 0;
+            int counter = Math.Min(l, 1000) + 1;
+            int[] working_set = new int[2];
+
+            while (true)
+            {
+                // show progress and do shrinking
+
+                if (--counter == 0)
+                {
+                    counter = Math.Min(l, 1000);
+                    if (shrinking) do_shrinking();
+                    Procedures.info(".");
+                }
+
+                if (select_working_set(working_set) != 0)
+                {
+                    // reconstruct the whole gradient
+                    reconstruct_gradient();
+                    // reset active set size and check
+                    active_size = l;
+                    Procedures.info("*");
+                    if (select_working_set(working_set) != 0)
+                        break;
+                    else
+                        counter = 1;	// do shrinking next iteration
+                }
+
+                int i = working_set[0];
+                int j = working_set[1];
+
+                ++iter;
+
+                // update alpha[i] and alpha[j], handle bounds carefully
+
+                float[] Q_i = Q.GetQ(i, active_size);
+                float[] Q_j = Q.GetQ(j, active_size);
+
+                double C_i = get_C(i);
+                double C_j = get_C(j);
+
+                double old_alpha_i = alpha[i];
+                double old_alpha_j = alpha[j];
+
+                if (y[i] != y[j])
+                {
+                    double quad_coef = Q_i[i] + Q_j[j] + 2 * Q_i[j];
+                    if (quad_coef <= 0)
+                        quad_coef = 1e-12;
+                    double delta = (-G[i] - G[j]) / quad_coef;
+                    double diff = alpha[i] - alpha[j];
+                    alpha[i] += delta;
+                    alpha[j] += delta;
+
+                    if (diff > 0)
+                    {
+                        if (alpha[j] < 0)
+                        {
+                            alpha[j] = 0;
+                            alpha[i] = diff;
+                        }
+                    }
+                    else
+                    {
+                        if (alpha[i] < 0)
+                        {
+                            alpha[i] = 0;
+                            alpha[j] = -diff;
+                        }
+                    }
+                    if (diff > C_i - C_j)
+                    {
+                        if (alpha[i] > C_i)
+                        {
+                            alpha[i] = C_i;
+                            alpha[j] = C_i - diff;
+                        }
+                    }
+                    else
+                    {
+                        if (alpha[j] > C_j)
+                        {
+                            alpha[j] = C_j;
+                            alpha[i] = C_j + diff;
+                        }
+                    }
+                }
+                else
+                {
+                    double quad_coef = Q_i[i] + Q_j[j] - 2 * Q_i[j];
+                    if (quad_coef <= 0)
+                        quad_coef = 1e-12;
+                    double delta = (G[i] - G[j]) / quad_coef;
+                    double sum = alpha[i] + alpha[j];
+                    alpha[i] -= delta;
+                    alpha[j] += delta;
+
+                    if (sum > C_i)
+                    {
+                        if (alpha[i] > C_i)
+                        {
+                            alpha[i] = C_i;
+                            alpha[j] = sum - C_i;
+                        }
+                    }
+                    else
+                    {
+                        if (alpha[j] < 0)
+                        {
+                            alpha[j] = 0;
+                            alpha[i] = sum;
+                        }
+                    }
+                    if (sum > C_j)
+                    {
+                        if (alpha[j] > C_j)
+                        {
+                            alpha[j] = C_j;
+                            alpha[i] = sum - C_j;
+                        }
+                    }
+                    else
+                    {
+                        if (alpha[i] < 0)
+                        {
+                            alpha[i] = 0;
+                            alpha[j] = sum;
+                        }
+                    }
+                }
+
+                // update G
+
+                double delta_alpha_i = alpha[i] - old_alpha_i;
+                double delta_alpha_j = alpha[j] - old_alpha_j;
+
+                for (int k = 0; k < active_size; k++)
+                {
+                    G[k] += Q_i[k] * delta_alpha_i + Q_j[k] * delta_alpha_j;
+                }
+
+                // update alpha_status and G_bar
+
+                {
+                    bool ui = is_upper_bound(i);
+                    bool uj = is_upper_bound(j);
+                    update_alpha_status(i);
+                    update_alpha_status(j);
+                    int k;
+                    if (ui != is_upper_bound(i))
+                    {
+                        Q_i = Q.GetQ(i, l);
+                        if (ui)
+                            for (k = 0; k < l; k++)
+                                G_bar[k] -= C_i * Q_i[k];
+                        else
+                            for (k = 0; k < l; k++)
+                                G_bar[k] += C_i * Q_i[k];
+                    }
+
+                    if (uj != is_upper_bound(j))
+                    {
+                        Q_j = Q.GetQ(j, l);
+                        if (uj)
+                            for (k = 0; k < l; k++)
+                                G_bar[k] -= C_j * Q_j[k];
+                        else
+                            for (k = 0; k < l; k++)
+                                G_bar[k] += C_j * Q_j[k];
+                    }
+                }
+
+            }
+
+            // calculate rho
+
+            si.rho = calculate_rho();
+
+            // calculate objective value
+            {
+                double v = 0;
+                int i;
+                for (i = 0; i < l; i++)
+                    v += alpha[i] * (G[i] + p[i]);
+
+                si.obj = v / 2;
+            }
+
+            // put back the solution
+            {
+                for (int i = 0; i < l; i++)
+                    alpha_[active_set[i]] = alpha[i];
+            }
+
+            si.upper_bound_p = Cp;
+            si.upper_bound_n = Cn;
+
+            Procedures.info("\noptimization finished, #iter = " + iter + "\n");
+        }
+
+        // return 1 if already optimal, return 0 otherwise
+        protected virtual int select_working_set(int[] working_set)
+        {
+            // return i,j such that
+            // i: Maximizes -y_i * grad(f)_i, i in I_up(\alpha)
+            // j: mimimizes the decrease of obj value
+            //    (if quadratic coefficeint <= 0, replace it with tau)
+            //    -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
+
+            double GMax = -INF;
+            double GMax2 = -INF;
+            int GMax_idx = -1;
+            int GMin_idx = -1;
+            double obj_diff_Min = INF;
+
+            for (int t = 0; t < active_size; t++)
+                if (y[t] == +1)
+                {
+                    if (!is_upper_bound(t))
+                        if (-G[t] >= GMax)
+                        {
+                            GMax = -G[t];
+                            GMax_idx = t;
+                        }
+                }
+                else
+                {
+                    if (!is_lower_bound(t))
+                        if (G[t] >= GMax)
+                        {
+                            GMax = G[t];
+                            GMax_idx = t;
+                        }
+                }
+
+            int i = GMax_idx;
+            float[] Q_i = null;
+            if (i != -1) // null Q_i not accessed: GMax=-INF if i=-1
+                Q_i = Q.GetQ(i, active_size);
+
+            for (int j = 0; j < active_size; j++)
+            {
+                if (y[j] == +1)
+                {
+                    if (!is_lower_bound(j))
+                    {
+                        double grad_diff = GMax + G[j];
+                        if (G[j] >= GMax2)
+                            GMax2 = G[j];
+                        if (grad_diff > 0)
+                        {
+                            double obj_diff;
+                            double quad_coef = Q_i[i] + QD[j] - 2.0 * y[i] * Q_i[j];
+                            if (quad_coef > 0)
+                                obj_diff = -(grad_diff * grad_diff) / quad_coef;
+                            else
+                                obj_diff = -(grad_diff * grad_diff) / 1e-12;
+
+                            if (obj_diff <= obj_diff_Min)
+                            {
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    if (!is_upper_bound(j))
+                    {
+                        double grad_diff = GMax - G[j];
+                        if (-G[j] >= GMax2)
+                            GMax2 = -G[j];
+                        if (grad_diff > 0)
+                        {
+                            double obj_diff;
+                            double quad_coef = Q_i[i] + QD[j] + 2.0 * y[i] * Q_i[j];
+                            if (quad_coef > 0)
+                                obj_diff = -(grad_diff * grad_diff) / quad_coef;
+                            else
+                                obj_diff = -(grad_diff * grad_diff) / 1e-12;
+
+                            if (obj_diff <= obj_diff_Min)
+                            {
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (GMax + GMax2 < EPS)
+                return 1;
+
+            working_set[0] = GMax_idx;
+            working_set[1] = GMin_idx;
+            return 0;
+        }
+
+        private bool be_shrunk(int i, double GMax1, double GMax2)
+        {
+            if (is_upper_bound(i))
+            {
+                if (y[i] == +1)
+                    return (-G[i] > GMax1);
+                else
+                    return (-G[i] > GMax2);
+            }
+            else if (is_lower_bound(i))
+            {
+                if (y[i] == +1)
+                    return (G[i] > GMax2);
+                else
+                    return (G[i] > GMax1);
+            }
+            else
+                return (false);
+        }
+
+        protected virtual void do_shrinking()
+        {
+            int i;
+            double GMax1 = -INF;		// Max { -y_i * grad(f)_i | i in I_up(\alpha) }
+            double GMax2 = -INF;		// Max { y_i * grad(f)_i | i in I_low(\alpha) }
+
+            // find Maximal violating pair first
+            for (i = 0; i < active_size; i++)
+            {
+                if (y[i] == +1)
+                {
+                    if (!is_upper_bound(i))
+                    {
+                        if (-G[i] >= GMax1)
+                            GMax1 = -G[i];
+                    }
+                    if (!is_lower_bound(i))
+                    {
+                        if (G[i] >= GMax2)
+                            GMax2 = G[i];
+                    }
+                }
+                else
+                {
+                    if (!is_upper_bound(i))
+                    {
+                        if (-G[i] >= GMax2)
+                            GMax2 = -G[i];
+                    }
+                    if (!is_lower_bound(i))
+                    {
+                        if (G[i] >= GMax1)
+                            GMax1 = G[i];
+                    }
+                }
+            }
+
+            if (unshrink == false && GMax1 + GMax2 <= EPS * 10)
+            {
+                unshrink = true;
+                reconstruct_gradient();
+                active_size = l;
+            }
+
+            for (i = 0; i < active_size; i++)
+                if (be_shrunk(i, GMax1, GMax2))
+                {
+                    active_size--;
+                    while (active_size > i)
+                    {
+                        if (!be_shrunk(active_size, GMax1, GMax2))
+                        {
+                            swap_index(i, active_size);
+                            break;
+                        }
+                        active_size--;
+                    }
+                }
+        }
+
+        protected virtual double calculate_rho()
+        {
+            double r;
+            int nr_free = 0;
+            double ub = INF, lb = -INF, sum_free = 0;
+            for (int i = 0; i < active_size; i++)
+            {
+                double yG = y[i] * G[i];
+
+                if (is_lower_bound(i))
+                {
+                    if (y[i] > 0)
+                        ub = Math.Min(ub, yG);
+                    else
+                        lb = Math.Max(lb, yG);
+                }
+                else if (is_upper_bound(i))
+                {
+                    if (y[i] < 0)
+                        ub = Math.Min(ub, yG);
+                    else
+                        lb = Math.Max(lb, yG);
+                }
+                else
+                {
+                    ++nr_free;
+                    sum_free += yG;
+                }
+            }
+
+            if (nr_free > 0)
+                r = sum_free / nr_free;
+            else
+                r = (ub + lb) / 2;
+
+            return r;
+        }
+
+    }
+
+    //
+    // Solver for nu-svm classification and regression
+    //
+    // additional constraint: e^T \alpha = constant
+    //
+    class Solver_NU : Solver
+    {
+        private SolutionInfo si;
+
+        public sealed override void Solve(int l, IQMatrix Q, double[] p, sbyte[] y,
+               double[] alpha, double Cp, double Cn, double eps,
+               SolutionInfo si, bool shrinking)
+        {
+            this.si = si;
+            base.Solve(l, Q, p, y, alpha, Cp, Cn, eps, si, shrinking);
+        }
+
+        // return 1 if already optimal, return 0 otherwise
+        protected override sealed int select_working_set(int[] working_set)
+        {
+            // return i,j such that y_i = y_j and
+            // i: Maximizes -y_i * grad(f)_i, i in I_up(\alpha)
+            // j: Minimizes the decrease of obj value
+            //    (if quadratic coefficeint <= 0, replace it with tau)
+            //    -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
+
+            double GMaxp = -INF;
+            double GMaxp2 = -INF;
+            int GMaxp_idx = -1;
+
+            double GMaxn = -INF;
+            double GMaxn2 = -INF;
+            int GMaxn_idx = -1;
+
+            int GMin_idx = -1;
+            double obj_diff_Min = INF;
+
+            for (int t = 0; t < active_size; t++)
+                if (y[t] == +1)
+                {
+                    if (!is_upper_bound(t))
+                        if (-G[t] >= GMaxp)
+                        {
+                            GMaxp = -G[t];
+                            GMaxp_idx = t;
+                        }
+                }
+                else
+                {
+                    if (!is_lower_bound(t))
+                        if (G[t] >= GMaxn)
+                        {
+                            GMaxn = G[t];
+                            GMaxn_idx = t;
+                        }
+                }
+
+            int ip = GMaxp_idx;
+            int iN = GMaxn_idx;
+            float[] Q_ip = null;
+            float[] Q_in = null;
+            if (ip != -1) // null Q_ip not accessed: GMaxp=-INF if ip=-1
+                Q_ip = Q.GetQ(ip, active_size);
+            if (iN != -1)
+                Q_in = Q.GetQ(iN, active_size);
+
+            for (int j = 0; j < active_size; j++)
+            {
+                if (y[j] == +1)
+                {
+                    if (!is_lower_bound(j))
+                    {
+                        double grad_diff = GMaxp + G[j];
+                        if (G[j] >= GMaxp2)
+                            GMaxp2 = G[j];
+                        if (grad_diff > 0)
+                        {
+                            double obj_diff;
+                            double quad_coef = Q_ip[ip] + QD[j] - 2 * Q_ip[j];
+                            if (quad_coef > 0)
+                                obj_diff = -(grad_diff * grad_diff) / quad_coef;
+                            else
+                                obj_diff = -(grad_diff * grad_diff) / 1e-12;
+
+                            if (obj_diff <= obj_diff_Min)
+                            {
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    if (!is_upper_bound(j))
+                    {
+                        double grad_diff = GMaxn - G[j];
+                        if (-G[j] >= GMaxn2)
+                            GMaxn2 = -G[j];
+                        if (grad_diff > 0)
+                        {
+                            double obj_diff;
+                            double quad_coef = Q_in[iN] + QD[j] - 2 * Q_in[j];
+                            if (quad_coef > 0)
+                                obj_diff = -(grad_diff * grad_diff) / quad_coef;
+                            else
+                                obj_diff = -(grad_diff * grad_diff) / 1e-12;
+
+                            if (obj_diff <= obj_diff_Min)
+                            {
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (Math.Max(GMaxp + GMaxp2, GMaxn + GMaxn2) < EPS)
+                return 1;
+
+            if (y[GMin_idx] == +1)
+                working_set[0] = GMaxp_idx;
+            else
+                working_set[0] = GMaxn_idx;
+            working_set[1] = GMin_idx;
+
+            return 0;
+        }
+
+        private bool be_shrunk(int i, double GMax1, double GMax2, double GMax3, double GMax4)
+        {
+            if (is_upper_bound(i))
+            {
+                if (y[i] == +1)
+                    return (-G[i] > GMax1);
+                else
+                    return (-G[i] > GMax4);
+            }
+            else if (is_lower_bound(i))
+            {
+                if (y[i] == +1)
+                    return (G[i] > GMax2);
+                else
+                    return (G[i] > GMax3);
+            }
+            else
+                return (false);
+        }
+
+        protected override sealed void do_shrinking()
+        {
+            double GMax1 = -INF;	// Max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) }
+            double GMax2 = -INF;	// Max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) }
+            double GMax3 = -INF;	// Max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) }
+            double GMax4 = -INF;	// Max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) }
+
+            // find Maximal violating pair first
+            int i;
+            for (i = 0; i < active_size; i++)
+            {
+                if (!is_upper_bound(i))
+                {
+                    if (y[i] == +1)
+                    {
+                        if (-G[i] > GMax1) GMax1 = -G[i];
+                    }
+                    else if (-G[i] > GMax4) GMax4 = -G[i];
+                }
+                if (!is_lower_bound(i))
+                {
+                    if (y[i] == +1)
+                    {
+                        if (G[i] > GMax2) GMax2 = G[i];
+                    }
+                    else if (G[i] > GMax3) GMax3 = G[i];
+                }
+            }
+
+            if (unshrink == false && Math.Max(GMax1 + GMax2, GMax3 + GMax4) <= EPS * 10)
+            {
+                unshrink = true;
+                reconstruct_gradient();
+                active_size = l;
+            }
+
+            for (i = 0; i < active_size; i++)
+                if (be_shrunk(i, GMax1, GMax2, GMax3, GMax4))
+                {
+                    active_size--;
+                    while (active_size > i)
+                    {
+                        if (!be_shrunk(active_size, GMax1, GMax2, GMax3, GMax4))
+                        {
+                            swap_index(i, active_size);
+                            break;
+                        }
+                        active_size--;
+                    }
+                }
+        }
+
+        protected override sealed double calculate_rho()
+        {
+            int nr_free1 = 0, nr_free2 = 0;
+            double ub1 = INF, ub2 = INF;
+            double lb1 = -INF, lb2 = -INF;
+            double sum_free1 = 0, sum_free2 = 0;
+
+            for (int i = 0; i < active_size; i++)
+            {
+                if (y[i] == +1)
+                {
+                    if (is_lower_bound(i))
+                        ub1 = Math.Min(ub1, G[i]);
+                    else if (is_upper_bound(i))
+                        lb1 = Math.Max(lb1, G[i]);
+                    else
+                    {
+                        ++nr_free1;
+                        sum_free1 += G[i];
+                    }
+                }
+                else
+                {
+                    if (is_lower_bound(i))
+                        ub2 = Math.Min(ub2, G[i]);
+                    else if (is_upper_bound(i))
+                        lb2 = Math.Max(lb2, G[i]);
+                    else
+                    {
+                        ++nr_free2;
+                        sum_free2 += G[i];
+                    }
+                }
+            }
+
+            double r1, r2;
+            if (nr_free1 > 0)
+                r1 = sum_free1 / nr_free1;
+            else
+                r1 = (ub1 + lb1) / 2;
+
+            if (nr_free2 > 0)
+                r2 = sum_free2 / nr_free2;
+            else
+                r2 = (ub2 + lb2) / 2;
+
+            si.r = (r1 + r2) / 2;
+            return (r1 - r2) / 2;
+        }
+    }
+
+    //
+    // Q matrices for various formulations
+    //
+    class SVC_Q : Kernel
+    {
+        private sbyte[] y;
+        private Cache cache;
+        private float[] QD;
+
+        public SVC_Q(Problem prob, Parameter param, sbyte[] y_) : base(prob.Count, prob.X, param)
+        {
+            y = (sbyte[])y_.Clone();
+            cache = new Cache(prob.Count, (long)(param.CacheSize * (1 << 20)));
+            QD = new float[prob.Count];
+            for (int i = 0; i < prob.Count; i++)
+                QD[i] = (float)KernelFunction(i, i);
+        }
+
+        public override sealed float[] GetQ(int i, int len)
+        {
+            float[] data = null;
+            int start, j;
+            if ((start = cache.GetData(i, ref data, len)) < len)
+            {
+                for (j = start; j < len; j++)
+                    data[j] = (float)(y[i] * y[j] * KernelFunction(i, j));
+            }
+            return data;
+        }
+
+        public override sealed float[] GetQD()
+        {
+            return QD;
+        }
+
+        public override sealed void SwapIndex(int i, int j)
+        {
+            cache.SwapIndex(i, j);
+            base.SwapIndex(i, j);
+            y.SwapIndex(i, j);
+            QD.SwapIndex(i, j);
+        }
+    }
+
+    class ONE_CLASS_Q : Kernel
+    {
+        private Cache cache;
+        private float[] QD;
+
+        public ONE_CLASS_Q(Problem prob, Parameter param) :  base(prob.Count, prob.X, param)
+        {
+            cache = new Cache(prob.Count, (long)(param.CacheSize * (1 << 20)));
+            QD = new float[prob.Count];
+            for (int i = 0; i < prob.Count; i++)
+                QD[i] = (float)KernelFunction(i, i);
+        }
+
+        public override sealed float[] GetQ(int i, int len)
+        {
+            float[] data = null;
+            int start, j;
+            if ((start = cache.GetData(i, ref data, len)) < len)
+            {
+                for (j = start; j < len; j++)
+                    data[j] = (float)KernelFunction(i, j);
+            }
+            return data;
+        }
+
+        public override sealed float[] GetQD()
+        {
+            return QD;
+        }
+
+        public override sealed void SwapIndex(int i, int j)
+        {
+            cache.SwapIndex(i, j);
+            base.SwapIndex(i, j);
+            QD.SwapIndex(i, j);
+        }
+    }
+
+    class SVR_Q : Kernel
+    {
+        private int l;
+        private Cache cache;
+        private sbyte[] sign;
+        private int[] index;
+        private int next_buffer;
+        private float[][] buffer;
+        private float[] QD;
+
+        public SVR_Q(Problem prob, Parameter param) : base(prob.Count, prob.X, param)
+        {
+            l = prob.Count;
+            cache = new Cache(l, (long)(param.CacheSize * (1 << 20)));
+            QD = new float[2 * l];
+            sign = new sbyte[2 * l];
+            index = new int[2 * l];
+            for (int k = 0; k < l; k++)
+            {
+                sign[k] = 1;
+                sign[k + l] = -1;
+                index[k] = k;
+                index[k + l] = k;
+                QD[k] = (float)KernelFunction(k, k);
+                QD[k + l] = QD[k];
+            }
+            buffer = new float[2][];
+            buffer[0] = new float[2 * l];
+            buffer[1] = new float[2 * l];
+            next_buffer = 0;
+        }
+
+        public override sealed void SwapIndex(int i, int j)
+        {
+            sign.SwapIndex(i, j);
+            index.SwapIndex(i, j);
+            QD.SwapIndex(i, j);
+        }
+
+        public override sealed float[] GetQ(int i, int len)
+        {
+            float[] data = null;
+            int j, real_i = index[i];
+            if (cache.GetData(real_i, ref data, l) < l)
+            {
+                for (j = 0; j < l; j++)
+                    data[j] = (float)KernelFunction(real_i, j);
+            }
+
+            // reorder and copy
+            float[] buf = buffer[next_buffer];
+            next_buffer = 1 - next_buffer;
+            sbyte si = sign[i];
+            for (j = 0; j < len; j++)
+                buf[j] = (float)si * sign[j] * data[index[j]];
+            return buf;
+        }
+
+        public override sealed float[] GetQD()
+        {
+            return QD;
+        }
+    }
+
+    internal class Procedures
+    {
+        private static bool _verbose;
+        public static bool IsVerbose
+        {
+            get
+            {
+                return _verbose;
+            }
+            set
+            {
+                _verbose = value;
+            }
+        }
+        //
+        // construct and solve various formulations
+        //
+        public const int LIBSVM_VERSION = 289;
+
+        public static TextWriter svm_print_string = Console.Out;
+
+        public static void info(string s)
+        {
+            if(_verbose)
+                svm_print_string.Write(s);
+        }
+
+        private static void solve_c_svc(Problem prob, Parameter param,
+                        double[] alpha, Solver.SolutionInfo si,
+                        double Cp, double Cn)
+        {
+            int l = prob.Count;
+            double[] Minus_ones = new double[l];
+            sbyte[] y = new sbyte[l];
+
+            int i;
+
+            for (i = 0; i < l; i++)
+            {
+                alpha[i] = 0;
+                Minus_ones[i] = -1;
+                if (prob.Y[i] > 0) y[i] = +1; else y[i] = -1;
+            }
+
+            Solver s = new Solver();
+            s.Solve(l, new SVC_Q(prob, param, y), Minus_ones, y,
+                alpha, Cp, Cn, param.EPS, si, param.Shrinking);
+
+            double sum_alpha = 0;
+            for (i = 0; i < l; i++)
+                sum_alpha += alpha[i];
+
+            if (Cp == Cn)
+                Procedures.info("nu = " + sum_alpha / (Cp * prob.Count) + "\n");
+
+            for (i = 0; i < l; i++)
+                alpha[i] *= y[i];
+        }
+
+        private static void solve_nu_svc(Problem prob, Parameter param,
+                        double[] alpha, Solver.SolutionInfo si)
+        {
+            int i;
+            int l = prob.Count;
+            double nu = param.Nu;
+
+            sbyte[] y = new sbyte[l];
+
+            for (i = 0; i < l; i++)
+                if (prob.Y[i] > 0)
+                    y[i] = +1;
+                else
+                    y[i] = -1;
+
+            double sum_pos = nu * l / 2;
+            double sum_neg = nu * l / 2;
+
+            for (i = 0; i < l; i++)
+                if (y[i] == +1)
+                {
+                    alpha[i] = Math.Min(1.0, sum_pos);
+                    sum_pos -= alpha[i];
+                }
+                else
+                {
+                    alpha[i] = Math.Min(1.0, sum_neg);
+                    sum_neg -= alpha[i];
+                }
+
+            double[] zeros = new double[l];
+
+            for (i = 0; i < l; i++)
+                zeros[i] = 0;
+
+            Solver_NU s = new Solver_NU();
+            s.Solve(l, new SVC_Q(prob, param, y), zeros, y, alpha, 1.0, 1.0, param.EPS, si, param.Shrinking);
+            double r = si.r;
+
+            Procedures.info("C = " + 1 / r + "\n");
+
+            for (i = 0; i < l; i++)
+                alpha[i] *= y[i] / r;
+
+            si.rho /= r;
+            si.obj /= (r * r);
+            si.upper_bound_p = 1 / r;
+            si.upper_bound_n = 1 / r;
+        }
+
+        private static void solve_one_class(Problem prob, Parameter param,
+                        double[] alpha, Solver.SolutionInfo si)
+        {
+            int l = prob.Count;
+            double[] zeros = new double[l];
+            sbyte[] ones = new sbyte[l];
+            int i;
+
+            int n = (int)(param.Nu * prob.Count);	// # of alpha's at upper bound
+
+            for (i = 0; i < n; i++)
+                alpha[i] = 1;
+            if (n < prob.Count)
+                alpha[n] = param.Nu * prob.Count - n;
+            for (i = n + 1; i < l; i++)
+                alpha[i] = 0;
+
+            for (i = 0; i < l; i++)
+            {
+                zeros[i] = 0;
+                ones[i] = 1;
+            }
+
+            Solver s = new Solver();
+            s.Solve(l, new ONE_CLASS_Q(prob, param), zeros, ones, alpha, 1.0, 1.0, param.EPS, si, param.Shrinking);
+        }
+
+        private static void solve_epsilon_svr(Problem prob, Parameter param, double[] alpha, Solver.SolutionInfo si)
+        {
+            int l = prob.Count;
+            double[] alpha2 = new double[2 * l];
+            double[] linear_term = new double[2 * l];
+            sbyte[] y = new sbyte[2 * l];
+            int i;
+
+            for (i = 0; i < l; i++)
+            {
+                alpha2[i] = 0;
+                linear_term[i] = param.P - prob.Y[i];
+                y[i] = 1;
+
+                alpha2[i + l] = 0;
+                linear_term[i + l] = param.P + prob.Y[i];
+                y[i + l] = -1;
+            }
+
+            Solver s = new Solver();
+            s.Solve(2 * l, new SVR_Q(prob, param), linear_term, y, alpha2, param.C, param.C, param.EPS, si, param.Shrinking);
+
+            double sum_alpha = 0;
+            for (i = 0; i < l; i++)
+            {
+                alpha[i] = alpha2[i] - alpha2[i + l];
+                sum_alpha += Math.Abs(alpha[i]);
+            }
+            Procedures.info("nu = " + sum_alpha / (param.C * l) + "\n");
+        }
+
+        private static void solve_nu_svr(Problem prob, Parameter param,
+                        double[] alpha, Solver.SolutionInfo si)
+        {
+            int l = prob.Count;
+            double C = param.C;
+            double[] alpha2 = new double[2 * l];
+            double[] linear_term = new double[2 * l];
+            sbyte[] y = new sbyte[2 * l];
+            int i;
+
+            double sum = C * param.Nu * l / 2;
+            for (i = 0; i < l; i++)
+            {
+                alpha2[i] = alpha2[i + l] = Math.Min(sum, C);
+                sum -= alpha2[i];
+
+                linear_term[i] = -prob.Y[i];
+                y[i] = 1;
+
+                linear_term[i + l] = prob.Y[i];
+                y[i + l] = -1;
+            }
+
+            Solver_NU s = new Solver_NU();
+            s.Solve(2 * l, new SVR_Q(prob, param), linear_term, y, alpha2, C, C, param.EPS, si, param.Shrinking);
+
+            Procedures.info("epsilon = " + (-si.r) + "\n");
+
+            for (i = 0; i < l; i++)
+                alpha[i] = alpha2[i] - alpha2[i + l];
+        }
+
+        //
+        // decision_function
+        //
+        internal class decision_function
+        {
+            public double[] alpha;
+            public double rho;
+        };
+
+        static decision_function svm_train_one(Problem prob, Parameter param, double Cp, double Cn)
+        {
+            double[] alpha = new double[prob.Count];
+            Solver.SolutionInfo si = new Solver.SolutionInfo();
+            switch (param.SvmType)
+            {
+                case SvmType.C_SVC:
+                    solve_c_svc(prob, param, alpha, si, Cp, Cn);
+                    break;
+                case SvmType.NU_SVC:
+                    solve_nu_svc(prob, param, alpha, si);
+                    break;
+                case SvmType.ONE_CLASS:
+                    solve_one_class(prob, param, alpha, si);
+                    break;
+                case SvmType.EPSILON_SVR:
+                    solve_epsilon_svr(prob, param, alpha, si);
+                    break;
+                case SvmType.NU_SVR:
+                    solve_nu_svr(prob, param, alpha, si);
+                    break;
+            }
+
+            Procedures.info("obj = " + si.obj + ", rho = " + si.rho + "\n");
+
+            // output SVs
+
+            int nSV = 0;
+            int nBSV = 0;
+            for (int i = 0; i < prob.Count; i++)
+            {
+                if (Math.Abs(alpha[i]) > 0)
+                {
+                    ++nSV;
+                    if (prob.Y[i] > 0)
+                    {
+                        if (Math.Abs(alpha[i]) >= si.upper_bound_p)
+                            ++nBSV;
+                    }
+                    else
+                    {
+                        if (Math.Abs(alpha[i]) >= si.upper_bound_n)
+                            ++nBSV;
+                    }
+                }
+            }
+
+            Procedures.info("nSV = " + nSV + ", nBSV = " + nBSV + "\n");
+
+            decision_function f = new decision_function();
+            f.alpha = alpha;
+            f.rho = si.rho;
+            return f;
+        }
+
+        // Platt's binary SVM Probablistic Output: an improvement from Lin et al.
+        private static void sigmoid_train(int l, double[] dec_values, double[] labels,
+                      double[] probAB)
+        {
+            double A, B;
+            double prior1 = 0, prior0 = 0;
+            int i;
+
+            for (i = 0; i < l; i++)
+                if (labels[i] > 0) prior1 += 1;
+                else prior0 += 1;
+
+            int Max_iter = 100;	// Maximal number of iterations
+            double Min_step = 1e-10;	// Minimal step taken in line search
+            double sigma = 1e-12;	// For numerically strict PD of Hessian
+            double eps = 1e-5;
+            double hiTarget = (prior1 + 1.0) / (prior1 + 2.0);
+            double loTarget = 1 / (prior0 + 2.0);
+            double[] t = new double[l];
+            double fApB, p, q, h11, h22, h21, g1, g2, det, dA, dB, gd, stepsize;
+            double newA, newB, newf, d1, d2;
+            int iter;
+
+            // Initial Point and Initial Fun Value
+            A = 0.0; B = Math.Log((prior0 + 1.0) / (prior1 + 1.0));
+            double fval = 0.0;
+
+            for (i = 0; i < l; i++)
+            {
+                if (labels[i] > 0) t[i] = hiTarget;
+                else t[i] = loTarget;
+                fApB = dec_values[i] * A + B;
+                if (fApB >= 0)
+                    fval += t[i] * fApB + Math.Log(1 + Math.Exp(-fApB));
+                else
+                    fval += (t[i] - 1) * fApB + Math.Log(1 + Math.Exp(fApB));
+            }
+            for (iter = 0; iter < Max_iter; iter++)
+            {
+                // Update Gradient and Hessian (use H' = H + sigma I)
+                h11 = sigma; // numerically ensures strict PD
+                h22 = sigma;
+                h21 = 0.0; g1 = 0.0; g2 = 0.0;
+                for (i = 0; i < l; i++)
+                {
+                    fApB = dec_values[i] * A + B;
+                    if (fApB >= 0)
+                    {
+                        p = Math.Exp(-fApB) / (1.0 + Math.Exp(-fApB));
+                        q = 1.0 / (1.0 + Math.Exp(-fApB));
+                    }
+                    else
+                    {
+                        p = 1.0 / (1.0 + Math.Exp(fApB));
+                        q = Math.Exp(fApB) / (1.0 + Math.Exp(fApB));
+                    }
+                    d2 = p * q;
+                    h11 += dec_values[i] * dec_values[i] * d2;
+                    h22 += d2;
+                    h21 += dec_values[i] * d2;
+                    d1 = t[i] - p;
+                    g1 += dec_values[i] * d1;
+                    g2 += d1;
+                }
+
+                // Stopping Criteria
+                if (Math.Abs(g1) < eps && Math.Abs(g2) < eps)
+                    break;
+
+                // Finding Newton direction: -inv(H') * g
+                det = h11 * h22 - h21 * h21;
+                dA = -(h22 * g1 - h21 * g2) / det;
+                dB = -(-h21 * g1 + h11 * g2) / det;
+                gd = g1 * dA + g2 * dB;
+
+
+                stepsize = 1;		// Line Search
+                while (stepsize >= Min_step)
+                {
+                    newA = A + stepsize * dA;
+                    newB = B + stepsize * dB;
+
+                    // New function value
+                    newf = 0.0;
+                    for (i = 0; i < l; i++)
+                    {
+                        fApB = dec_values[i] * newA + newB;
+                        if (fApB >= 0)
+                            newf += t[i] * fApB + Math.Log(1 + Math.Exp(-fApB));
+                        else
+                            newf += (t[i] - 1) * fApB + Math.Log(1 + Math.Exp(fApB));
+                    }
+                    // Check sufficient decrease
+                    if (newf < fval + 0.0001 * stepsize * gd)
+                    {
+                        A = newA; B = newB; fval = newf;
+                        break;
+                    }
+                    else
+                        stepsize = stepsize / 2.0;
+                }
+
+                if (stepsize < Min_step)
+                {
+                    Procedures.info("Line search fails in two-class probability estimates\n");
+                    break;
+                }
+            }
+
+            if (iter >= Max_iter)
+                Procedures.info("Reaching Maximal iterations in two-class probability estimates\n");
+            probAB[0] = A; probAB[1] = B;
+        }
+
+        private static double sigmoid_predict(double decision_value, double A, double B)
+        {
+            double fApB = decision_value * A + B;
+            if (fApB >= 0)
+                return Math.Exp(-fApB) / (1.0 + Math.Exp(-fApB));
+            else
+                return 1.0 / (1 + Math.Exp(fApB));
+        }
+
+        // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng
+        private static void multiclass_probability(int k, double[,] r, double[] p)
+        {
+            int t, j;
+            int iter = 0, Max_iter = Math.Max(100, k);
+            double[,] Q = new double[k,k];
+            double[] Qp = new double[k];
+            double pQp, eps = 0.005 / k;
+
+            for (t = 0; t < k; t++)
+            {
+                p[t] = 1.0 / k;  // Valid if k = 1
+                Q[t,t] = 0;
+                for (j = 0; j < t; j++)
+                {
+                    Q[t,t] += r[j,t] * r[j,t];
+                    Q[t,j] = Q[j,t];
+                }
+                for (j = t + 1; j < k; j++)
+                {
+                    Q[t,t] += r[j,t] * r[j,t];
+                    Q[t,j] = -r[j,t] * r[t,j];
+                }
+            }
+            for (iter = 0; iter < Max_iter; iter++)
+            {
+                // stopping condition, recalculate QP,pQP for numerical accuracy
+                pQp = 0;
+                for (t = 0; t < k; t++)
+                {
+                    Qp[t] = 0;
+                    for (j = 0; j < k; j++)
+                        Qp[t] += Q[t,j] * p[j];
+                    pQp += p[t] * Qp[t];
+                }
+                double Max_error = 0;
+                for (t = 0; t < k; t++)
+                {
+                    double error = Math.Abs(Qp[t] - pQp);
+                    if (error > Max_error)
+                        Max_error = error;
+                }
+                if (Max_error < eps) break;
+
+                for (t = 0; t < k; t++)
+                {
+                    double diff = (-Qp[t] + pQp) / Q[t,t];
+                    p[t] += diff;
+                    pQp = (pQp + diff * (diff * Q[t,t] + 2 * Qp[t])) / (1 + diff) / (1 + diff);
+                    for (j = 0; j < k; j++)
+                    {
+                        Qp[j] = (Qp[j] + diff * Q[t,j]) / (1 + diff);
+                        p[j] /= (1 + diff);
+                    }
+                }
+            }
+            if (iter >= Max_iter)
+                Procedures.info("Exceeds Max_iter in multiclass_prob\n");
+        }
+
+        // Cross-validation decision values for probability estimates
+        private static void svm_binary_svc_probability(Problem prob, Parameter param, double Cp, double Cn, double[] probAB)
+        {
+            int i;
+            int nr_fold = 5;
+            int[] perm = new int[prob.Count];
+            double[] dec_values = new double[prob.Count];
+
+            // random shuffle
+            Random rand = new Random();
+            for (i = 0; i < prob.Count; i++) perm[i] = i;
+            for (i = 0; i < prob.Count; i++)
+            {
+                int j = i + (int)(rand.NextDouble() * (prob.Count - i));
+                do { int _ = perm[i]; perm[i] = perm[j]; perm[j] = _; } while (false);
+            }
+            for (i = 0; i < nr_fold; i++)
+            {
+                int begin = i * prob.Count / nr_fold;
+                int end = (i + 1) * prob.Count / nr_fold;
+                int j, k;
+                Problem subprob = new Problem();
+
+                subprob.Count = prob.Count - (end - begin);
+                subprob.X = new Node[subprob.Count][];
+                subprob.Y = new double[subprob.Count];
+
+                k = 0;
+                for (j = 0; j < begin; j++)
+                {
+                    subprob.X[k] = prob.X[perm[j]];
+                    subprob.Y[k] = prob.Y[perm[j]];
+                    ++k;
+                }
+                for (j = end; j < prob.Count; j++)
+                {
+                    subprob.X[k] = prob.X[perm[j]];
+                    subprob.Y[k] = prob.Y[perm[j]];
+                    ++k;
+                }
+                int p_count = 0, n_count = 0;
+                for (j = 0; j < k; j++)
+                    if (subprob.Y[j] > 0)
+                        p_count++;
+                    else
+                        n_count++;
+
+                if (p_count == 0 && n_count == 0)
+                    for (j = begin; j < end; j++)
+                        dec_values[perm[j]] = 0;
+                else if (p_count > 0 && n_count == 0)
+                    for (j = begin; j < end; j++)
+                        dec_values[perm[j]] = 1;
+                else if (p_count == 0 && n_count > 0)
+                    for (j = begin; j < end; j++)
+                        dec_values[perm[j]] = -1;
+                else
+                {
+                    Parameter subparam = (Parameter)param.Clone();
+                    subparam.Probability = false;
+                    subparam.C = 1.0;
+                    subparam.Weights[1] = Cp;
+                    subparam.Weights[-1] = Cn;
+                    Model submodel = svm_train(subprob, subparam);
+                    for (j = begin; j < end; j++)
+                    {
+                        double[] dec_value = new double[1];
+                        svm_predict_values(submodel, prob.X[perm[j]], dec_value);
+                        dec_values[perm[j]] = dec_value[0];
+                        // ensure +1 -1 order; reason not using CV subroutine
+                        dec_values[perm[j]] *= submodel.ClassLabels[0];
+                    }
+                }
+            }
+            sigmoid_train(prob.Count, dec_values, prob.Y, probAB);
+        }
+
+        // Return parameter of a Laplace distribution 
+        private static double svm_svr_probability(Problem prob, Parameter param)
+        {
+            int i;
+            int nr_fold = 5;
+            double[] ymv = new double[prob.Count];
+            double mae = 0;
+
+            Parameter newparam = (Parameter)param.Clone();
+            newparam.Probability = false;
+            svm_cross_validation(prob, newparam, nr_fold, ymv);
+            for (i = 0; i < prob.Count; i++)
+            {
+                ymv[i] = prob.Y[i] - ymv[i];
+                mae += Math.Abs(ymv[i]);
+            }
+            mae /= prob.Count;
+            double std = Math.Sqrt(2 * mae * mae);
+            int count = 0;
+            mae = 0;
+            for (i = 0; i < prob.Count; i++)
+                if (Math.Abs(ymv[i]) > 5 * std)
+                    count = count + 1;
+                else
+                    mae += Math.Abs(ymv[i]);
+            mae /= (prob.Count - count);
+            Procedures.info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + mae + "\n");
+            return mae;
+        }
+
+        // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data
+        // perm, length l, must be allocated before calling this subroutine
+        private static void svm_group_classes(Problem prob, int[] nr_class_ret, int[][] label_ret, int[][] start_ret, int[][] count_ret, int[] perm)
+        {
+            int l = prob.Count;
+            int Max_nr_class = 16;
+            int nr_class = 0;
+            int[] label = new int[Max_nr_class];
+            int[] count = new int[Max_nr_class];
+            int[] data_label = new int[l];
+            int i;
+
+            for (i = 0; i < l; i++)
+            {
+                int this_label = (int)(prob.Y[i]);
+                int j;
+                for (j = 0; j < nr_class; j++)
+                {
+                    if (this_label == label[j])
+                    {
+                        ++count[j];
+                        break;
+                    }
+                }
+                data_label[i] = j;
+                if (j == nr_class)
+                {
+                    if (nr_class == Max_nr_class)
+                    {
+                        Max_nr_class *= 2;
+                        int[] new_data = new int[Max_nr_class];
+                        Array.Copy(label, 0, new_data, 0, label.Length);
+                        label = new_data;
+                        new_data = new int[Max_nr_class];
+                        Array.Copy(count, 0, new_data, 0, count.Length);
+                        count = new_data;
+                    }
+                    label[nr_class] = this_label;
+                    count[nr_class] = 1;
+                    ++nr_class;
+                }
+            }
+
+            int[] start = new int[nr_class];
+            start[0] = 0;
+            for (i = 1; i < nr_class; i++)
+                start[i] = start[i - 1] + count[i - 1];
+            for (i = 0; i < l; i++)
+            {
+                perm[start[data_label[i]]] = i;
+                ++start[data_label[i]];
+            }
+            start[0] = 0;
+            for (i = 1; i < nr_class; i++)
+                start[i] = start[i - 1] + count[i - 1];
+
+            nr_class_ret[0] = nr_class;
+            label_ret[0] = label;
+            start_ret[0] = start;
+            count_ret[0] = count;
+        }
+
+        //
+        // Interface functions
+        //
+        public static Model svm_train(Problem prob, Parameter param)
+        {
+            Model model = new Model();
+            model.Parameter = param;
+
+            if (param.SvmType == SvmType.ONE_CLASS || 
+               param.SvmType == SvmType.EPSILON_SVR ||
+               param.SvmType == SvmType.NU_SVR)
+            {
+                // regression or one-class-svm
+                model.NumberOfClasses = 2;                
+                model.ClassLabels = null;
+                model.NumberOfSVPerClass = null;
+                model.PairwiseProbabilityA = null; model.PairwiseProbabilityB = null;
+                model.SupportVectorCoefficients = new double[1][];
+                
+                if (param.Probability &&
+                   (param.SvmType == SvmType.EPSILON_SVR ||
+                    param.SvmType == SvmType.NU_SVR))
+                {
+                    model.PairwiseProbabilityA = new double[1];
+                    model.PairwiseProbabilityA[0] = svm_svr_probability(prob, param);
+                }
+
+                decision_function f = svm_train_one(prob, param, 0, 0);
+                model.Rho = new double[1];
+                model.Rho[0] = f.rho;
+
+                int nSV = 0;
+                int i;
+                for (i = 0; i < prob.Count; i++)
+                    if (Math.Abs(f.alpha[i]) > 0) ++nSV;                
+                model.SupportVectorCount = nSV;
+                model.SupportVectors = new Node[nSV][];
+                model.SupportVectorCoefficients[0] = new double[nSV];
+                int j = 0;
+                for (i = 0; i < prob.Count; i++)
+                    if (Math.Abs(f.alpha[i]) > 0)
+                    {
+                        model.SupportVectors[j] = prob.X[i];
+                        model.SupportVectorCoefficients[0][j] = f.alpha[i];
+                        ++j;
+                    }
+            }
+            else
+            {
+                // classification
+                int l = prob.Count;
+                int[] tmp_nr_class = new int[1];
+                int[][] tmp_label = new int[1][];
+                int[][] tmp_start = new int[1][];
+                int[][] tmp_count = new int[1][];
+                int[] perm = new int[l];
+
+                // group training data of the same class
+                svm_group_classes(prob, tmp_nr_class, tmp_label, tmp_start, tmp_count, perm);
+                int nr_class = tmp_nr_class[0];
+                int[] label = tmp_label[0];
+                int[] start = tmp_start[0];
+                int[] count = tmp_count[0];
+                Node[][] x = new Node[l][];
+                int i;
+                for (i = 0; i < l; i++)
+                    x[i] = prob.X[perm[i]];
+
+                // calculate weighted C
+
+                double[] weighted_C = new double[nr_class];
+                for (i = 0; i < nr_class; i++)
+                    weighted_C[i] = param.C;
+                foreach (int weightedLabel in param.Weights.Keys)
+                {
+                    int index = Array.IndexOf<int>(label, weightedLabel);
+                    if (index < 0)
+                        Console.Error.WriteLine("warning: class label " + weightedLabel + " specified in weight is not found");
+                    else weighted_C[index] *= param.Weights[weightedLabel];
+                }
+
+                // train k*(k-1)/2 models
+
+                bool[] nonzero = new bool[l];
+                for (i = 0; i < l; i++)
+                    nonzero[i] = false;
+                decision_function[] f = new decision_function[nr_class * (nr_class - 1) / 2];
+
+                double[] probA = null, probB = null;
+                if (param.Probability)
+                {
+                    probA = new double[nr_class * (nr_class - 1) / 2];
+                    probB = new double[nr_class * (nr_class - 1) / 2];
+                }
+
+                int p = 0;
+                for (i = 0; i < nr_class; i++)
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        Problem sub_prob = new Problem();
+                        int si = start[i], sj = start[j];
+                        int ci = count[i], cj = count[j];
+                        sub_prob.Count = ci + cj;
+                        sub_prob.X = new Node[sub_prob.Count][];
+                        sub_prob.Y = new double[sub_prob.Count];
+                        int k;
+                        for (k = 0; k < ci; k++)
+                        {
+                            sub_prob.X[k] = x[si + k];
+                            sub_prob.Y[k] = +1;
+                        }
+                        for (k = 0; k < cj; k++)
+                        {
+                            sub_prob.X[ci + k] = x[sj + k];
+                            sub_prob.Y[ci + k] = -1;
+                        }
+
+                        if (param.Probability)
+                        {
+                            double[] probAB = new double[2];
+                            svm_binary_svc_probability(sub_prob, param, weighted_C[i], weighted_C[j], probAB);
+                            probA[p] = probAB[0];
+                            probB[p] = probAB[1];
+                        }
+
+                        f[p] = svm_train_one(sub_prob, param, weighted_C[i], weighted_C[j]);
+                        for (k = 0; k < ci; k++)
+                            if (!nonzero[si + k] && Math.Abs(f[p].alpha[k]) > 0)
+                                nonzero[si + k] = true;
+                        for (k = 0; k < cj; k++)
+                            if (!nonzero[sj + k] && Math.Abs(f[p].alpha[ci + k]) > 0)
+                                nonzero[sj + k] = true;
+                        ++p;
+                    }
+
+                // build output
+
+                model.NumberOfClasses = nr_class;
+
+                model.ClassLabels = new int[nr_class];
+                for (i = 0; i < nr_class; i++)
+                    model.ClassLabels[i] = label[i];
+
+                model.Rho = new double[nr_class * (nr_class - 1) / 2];
+                for (i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+                    model.Rho[i] = f[i].rho;
+
+                if (param.Probability)
+                {
+                    model.PairwiseProbabilityA = new double[nr_class * (nr_class - 1) / 2];
+                    model.PairwiseProbabilityB = new double[nr_class * (nr_class - 1) / 2];
+                    for (i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+                    {
+                        model.PairwiseProbabilityA[i] = probA[i];
+                        model.PairwiseProbabilityB[i] = probB[i];
+                    }
+                }
+                else
+                {
+                    model.PairwiseProbabilityA = null;
+                    model.PairwiseProbabilityB = null;
+                }
+
+                int nnz = 0;
+                int[] nz_count = new int[nr_class];
+                model.NumberOfSVPerClass = new int[nr_class];
+                for (i = 0; i < nr_class; i++)
+                {
+                    int nSV = 0;
+                    for (int j = 0; j < count[i]; j++)
+                        if (nonzero[start[i] + j])
+                        {
+                            ++nSV;
+                            ++nnz;
+                        }
+                    model.NumberOfSVPerClass[i] = nSV;
+                    nz_count[i] = nSV;
+                }
+
+                Procedures.info("Total nSV = " + nnz + "\n");
+
+                model.SupportVectorCount = nnz;
+                model.SupportVectors = new Node[nnz][];
+                p = 0;
+                for (i = 0; i < l; i++)
+                    if (nonzero[i]) model.SupportVectors[p++] = x[i];
+
+                int[] nz_start = new int[nr_class];
+                nz_start[0] = 0;
+                for (i = 1; i < nr_class; i++)
+                    nz_start[i] = nz_start[i - 1] + nz_count[i - 1];
+
+                model.SupportVectorCoefficients = new double[nr_class - 1][];
+                for (i = 0; i < nr_class - 1; i++)
+                    model.SupportVectorCoefficients[i] = new double[nnz];
+
+                p = 0;
+                for (i = 0; i < nr_class; i++)
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        // classifier (i,j): coefficients with
+                        // i are in sv_coef[j-1][nz_start[i]...],
+                        // j are in sv_coef[i][nz_start[j]...]
+
+                        int si = start[i];
+                        int sj = start[j];
+                        int ci = count[i];
+                        int cj = count[j];
+
+                        int q = nz_start[i];
+                        int k;
+                        for (k = 0; k < ci; k++)
+                            if (nonzero[si + k])
+                                model.SupportVectorCoefficients[j - 1][q++] = f[p].alpha[k];
+                        q = nz_start[j];
+                        for (k = 0; k < cj; k++)
+                            if (nonzero[sj + k])
+                                model.SupportVectorCoefficients[i][q++] = f[p].alpha[ci + k];
+                        ++p;
+                    }
+            }
+            return model;
+        }
+
+        // Stratified cross validation
+        public static void svm_cross_validation(Problem prob, Parameter param, int nr_fold, double[] target)
+        {
+            Random rand = new Random();
+            int i;
+            int[] fold_start = new int[nr_fold + 1];
+            int l = prob.Count;
+            int[] perm = new int[l];
+
+            // stratified cv may not give leave-one-out rate
+            // Each class to l folds -> some folds may have zero elements
+            if ((param.SvmType == SvmType.C_SVC ||
+                param.SvmType == SvmType.NU_SVC) && nr_fold < l)
+            {
+                int[] tmp_nr_class = new int[1];
+                int[][] tmp_label = new int[1][];
+                int[][] tmp_start = new int[1][];
+                int[][] tmp_count = new int[1][];
+
+                svm_group_classes(prob, tmp_nr_class, tmp_label, tmp_start, tmp_count, perm);
+
+                int nr_class = tmp_nr_class[0];
+                int[] label = tmp_label[0];
+                int[] start = tmp_start[0];
+                int[] count = tmp_count[0];
+
+                // random shuffle and then data grouped by fold using the array perm
+                int[] fold_count = new int[nr_fold];
+                int c;
+                int[] index = new int[l];
+                for (i = 0; i < l; i++)
+                    index[i] = perm[i];
+                for (c = 0; c < nr_class; c++)
+                    for (i = 0; i < count[c]; i++)
+                    {
+                        int j = i + (int)(rand.NextDouble() * (count[c] - i));
+                        do { int _ = index[start[c] + j]; index[start[c] + j] = index[start[c] + i]; index[start[c] + i] = _; } while (false);
+                    }
+                for (i = 0; i < nr_fold; i++)
+                {
+                    fold_count[i] = 0;
+                    for (c = 0; c < nr_class; c++)
+                        fold_count[i] += (i + 1) * count[c] / nr_fold - i * count[c] / nr_fold;
+                }
+                fold_start[0] = 0;
+                for (i = 1; i <= nr_fold; i++)
+                    fold_start[i] = fold_start[i - 1] + fold_count[i - 1];
+                for (c = 0; c < nr_class; c++)
+                    for (i = 0; i < nr_fold; i++)
+                    {
+                        int begin = start[c] + i * count[c] / nr_fold;
+                        int end = start[c] + (i + 1) * count[c] / nr_fold;
+                        for (int j = begin; j < end; j++)
+                        {
+                            perm[fold_start[i]] = index[j];
+                            fold_start[i]++;
+                        }
+                    }
+                fold_start[0] = 0;
+                for (i = 1; i <= nr_fold; i++)
+                    fold_start[i] = fold_start[i - 1] + fold_count[i - 1];
+            }
+            else
+            {
+                for (i = 0; i < l; i++) perm[i] = i;
+                for (i = 0; i < l; i++)
+                {
+                    int j = i + (int)(rand.NextDouble() * (l - i));
+                    do { int _ = perm[i]; perm[i] = perm[j]; perm[j] = _; } while (false);
+                }
+                for (i = 0; i <= nr_fold; i++)
+                    fold_start[i] = i * l / nr_fold;
+            }
+
+            for (i = 0; i < nr_fold; i++)
+            {
+                int begin = fold_start[i];
+                int end = fold_start[i + 1];
+                int j, k;
+                Problem subprob = new Problem();
+
+                subprob.Count = l - (end - begin);
+                subprob.X = new Node[subprob.Count][];
+                subprob.Y = new double[subprob.Count];
+
+                k = 0;
+                for (j = 0; j < begin; j++)
+                {
+                    subprob.X[k] = prob.X[perm[j]];
+                    subprob.Y[k] = prob.Y[perm[j]];
+                    ++k;
+                }
+                for (j = end; j < l; j++)
+                {
+                    subprob.X[k] = prob.X[perm[j]];
+                    subprob.Y[k] = prob.Y[perm[j]];
+                    ++k;
+                }
+                Model submodel = svm_train(subprob, param);
+                if (param.Probability &&
+                   (param.SvmType == SvmType.C_SVC ||
+                    param.SvmType == SvmType.NU_SVC))
+                {
+                    double[] prob_estimates = new double[svm_get_nr_class(submodel)];
+                    for (j = begin; j < end; j++)
+                        target[perm[j]] = svm_predict_probability(submodel, prob.X[perm[j]], prob_estimates);
+                }
+                else
+                    for (j = begin; j < end; j++)
+                        target[perm[j]] = svm_predict(submodel, prob.X[perm[j]]);
+            }
+        }
+
+        public static SvmType svm_get_svm_type(Model model)
+        {
+            return model.Parameter.SvmType;
+        }
+
+        public static int svm_get_nr_class(Model model)
+        {
+            return model.NumberOfClasses;
+        }
+
+        public static void svm_get_labels(Model model, int[] label)
+        {
+            if (model.ClassLabels != null)
+                for (int i = 0; i < model.NumberOfClasses; i++)
+                    label[i] = model.ClassLabels[i];
+        }
+
+        public static double svm_get_svr_probability(Model model)
+        {
+            if ((model.Parameter.SvmType == SvmType.EPSILON_SVR || model.Parameter.SvmType == SvmType.NU_SVR) &&
+                model.PairwiseProbabilityA != null)
+                return model.PairwiseProbabilityA[0];
+            else
+            {
+                Console.Error.WriteLine("Model doesn't contain information for SVR probability inference");
+                return 0;
+            }
+        }
+
+        public static void svm_predict_values(Model model, Node[] x, double[] dec_values)
+        {
+            if (model.Parameter.SvmType == SvmType.ONE_CLASS ||
+               model.Parameter.SvmType == SvmType.EPSILON_SVR ||
+               model.Parameter.SvmType == SvmType.NU_SVR)
+            {
+                double[] sv_coef = model.SupportVectorCoefficients[0];
+                double sum = 0;
+                for (int i = 0; i < model.SupportVectorCount; i++)
+                    sum += sv_coef[i] * Kernel.KernelFunction(x, model.SupportVectors[i], model.Parameter);
+                sum -= model.Rho[0];
+                dec_values[0] = sum;
+            }
+            else
+            {
+                int i;
+                int nr_class = model.NumberOfClasses;
+                int l = model.SupportVectorCount;
+
+                double[] kvalue = new double[l];
+                for (i = 0; i < l; i++)
+                    kvalue[i] = Kernel.KernelFunction(x, model.SupportVectors[i], model.Parameter);
+
+                int[] start = new int[nr_class];
+                start[0] = 0;
+                for (i = 1; i < nr_class; i++)
+                    start[i] = start[i - 1] + model.NumberOfSVPerClass[i - 1];
+
+                int p = 0;
+                for (i = 0; i < nr_class; i++)
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        double sum = 0;
+                        int si = start[i];
+                        int sj = start[j];
+                        int ci = model.NumberOfSVPerClass[i];
+                        int cj = model.NumberOfSVPerClass[j];
+
+                        int k;
+                        double[] coef1 = model.SupportVectorCoefficients[j - 1];
+                        double[] coef2 = model.SupportVectorCoefficients[i];
+                        for (k = 0; k < ci; k++)
+                            sum += coef1[si + k] * kvalue[si + k];
+                        for (k = 0; k < cj; k++)
+                            sum += coef2[sj + k] * kvalue[sj + k];
+                        sum -= model.Rho[p];
+                        dec_values[p] = sum;
+                        p++;
+                    }
+            }
+        }
+
+        public static double svm_predict(Model model, Node[] x)
+        {
+            if (model.Parameter.SvmType == SvmType.ONE_CLASS ||
+               model.Parameter.SvmType == SvmType.EPSILON_SVR ||
+               model.Parameter.SvmType == SvmType.NU_SVR)
+            {
+                double[] res = new double[1];
+                svm_predict_values(model, x, res);
+
+                if (model.Parameter.SvmType == SvmType.ONE_CLASS)
+                    return (res[0] > 0) ? 1 : -1;
+                else
+                    return res[0];
+            }
+            else
+            {
+                int i;
+                int nr_class = model.NumberOfClasses;
+                double[] dec_values = new double[nr_class * (nr_class - 1) / 2];
+                svm_predict_values(model, x, dec_values);
+
+                int[] vote = new int[nr_class];
+                for (i = 0; i < nr_class; i++)
+                    vote[i] = 0;
+                int pos = 0;
+                for (i = 0; i < nr_class; i++)
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        if (dec_values[pos++] > 0)
+                            ++vote[i];
+                        else
+                            ++vote[j];
+                    }
+
+                int vote_Max_idx = 0;
+                for (i = 1; i < nr_class; i++)
+                    if (vote[i] > vote[vote_Max_idx])
+                        vote_Max_idx = i;
+                return model.ClassLabels[vote_Max_idx];
+            }
+        }
+
+        public static double svm_predict_probability(Model model, Node[] x, double[] prob_estimates)
+        {
+            if ((model.Parameter.SvmType == SvmType.C_SVC || model.Parameter.SvmType == SvmType.NU_SVC) &&
+                model.PairwiseProbabilityA != null && model.PairwiseProbabilityB != null)
+            {
+                int i;
+                int nr_class = model.NumberOfClasses;
+                double[] dec_values = new double[nr_class * (nr_class - 1) / 2];
+                svm_predict_values(model, x, dec_values);
+
+                double Min_prob = 1e-7;
+                double[,] pairwise_prob = new double[nr_class, nr_class];
+
+                int k = 0;
+                for (i = 0; i < nr_class; i++)
+                {
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        pairwise_prob[i, j] = Math.Min(Math.Max(sigmoid_predict(dec_values[k], model.PairwiseProbabilityA[k], model.PairwiseProbabilityB[k]), Min_prob), 1 - Min_prob);
+                        pairwise_prob[j, i] = 1 - pairwise_prob[i, j];
+                        k++;
+                    }
+                }
+                multiclass_probability(nr_class, pairwise_prob, prob_estimates);
+
+                int prob_Max_idx = 0;
+                for (i = 1; i < nr_class; i++)
+                    if (prob_estimates[i] > prob_estimates[prob_Max_idx])
+                        prob_Max_idx = i;
+                return model.ClassLabels[prob_Max_idx];
+            }
+            else
+                return svm_predict(model, x);
+        }
+
+        public static string svm_check_parameter(Problem prob, Parameter param)
+        {
+            // svm_type
+
+            SvmType svm_type = param.SvmType;
+
+            // kernel_type, degree
+
+            KernelType kernel_type = param.KernelType;
+
+            if (param.Degree < 0)
+                return "degree of polynomial kernel < 0";
+
+            // cache_size,eps,C,nu,p,shrinking
+
+            if (param.CacheSize <= 0)
+                return "cache_size <= 0";
+
+            if (param.EPS <= 0)
+                return "eps <= 0";
+
+            if (param.Gamma == 0)
+                param.Gamma = 1.0 / prob.MaxIndex;
+
+            if (svm_type == SvmType.C_SVC ||
+               svm_type == SvmType.EPSILON_SVR ||
+               svm_type == SvmType.NU_SVR)
+                if (param.C <= 0)
+                    return "C <= 0";
+
+            if (svm_type == SvmType.NU_SVC ||
+               svm_type == SvmType.ONE_CLASS ||
+               svm_type == SvmType.NU_SVR)
+                if (param.Nu <= 0 || param.Nu > 1)
+                    return "nu <= 0 or nu > 1";
+
+            if (svm_type == SvmType.EPSILON_SVR)
+                if (param.P < 0)
+                    return "p < 0";
+
+            if (param.Probability &&
+               svm_type == SvmType.ONE_CLASS)
+                return "one-class SVM probability output not supported yet";
+
+            // check whether nu-svc is feasible
+
+            if (svm_type == SvmType.NU_SVC)
+            {
+                int l = prob.Count;
+                int Max_nr_class = 16;
+                int nr_class = 0;
+                int[] label = new int[Max_nr_class];
+                int[] count = new int[Max_nr_class];
+
+                int i;
+                for (i = 0; i < l; i++)
+                {
+                    int this_label = (int)prob.Y[i];
+                    int j;
+                    for (j = 0; j < nr_class; j++)
+                        if (this_label == label[j])
+                        {
+                            ++count[j];
+                            break;
+                        }
+
+                    if (j == nr_class)
+                    {
+                        if (nr_class == Max_nr_class)
+                        {
+                            Max_nr_class *= 2;
+                            int[] new_data = new int[Max_nr_class];
+                            Array.Copy(label, 0, new_data, 0, label.Length);
+                            label = new_data;
+
+                            new_data = new int[Max_nr_class];
+                            Array.Copy(count, 0, new_data, 0, count.Length);
+                            count = new_data;
+                        }
+                        label[nr_class] = this_label;
+                        count[nr_class] = 1;
+                        ++nr_class;
+                    }
+                }
+
+                for (i = 0; i < nr_class; i++)
+                {
+                    int n1 = count[i];
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        int n2 = count[j];
+                        if (param.Nu * (n1 + n2) / 2 > Math.Min(n1, n2))
+                            return "specified nu is infeasible";
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        public static int svm_check_probability_model(Model model)
+        {
+            if (((model.Parameter.SvmType == SvmType.C_SVC || model.Parameter.SvmType == SvmType.NU_SVC) &&
+            model.PairwiseProbabilityA != null && model.PairwiseProbabilityB != null) ||
+            ((model.Parameter.SvmType == SvmType.EPSILON_SVR || model.Parameter.SvmType == SvmType.NU_SVR) &&
+             model.PairwiseProbabilityA != null))
+                return 1;
+            else
+                return 0;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/TemporaryCulture.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/TemporaryCulture.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/TemporaryCulture.cs	(revision 2645)
@@ -0,0 +1,25 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Globalization;
+using System.Threading;
+
+namespace SVM
+{
+    internal static class TemporaryCulture
+    {
+        private static CultureInfo _culture;
+
+        public static void Start()
+        {
+            _culture = Thread.CurrentThread.CurrentCulture;
+            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+        }
+
+        public static void Stop()
+        {
+            Thread.CurrentThread.CurrentCulture = _culture;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Training.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Training.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.LibSVM/1.6.3/LibSVM-1.6.3/Training.cs	(revision 2645)
@@ -0,0 +1,226 @@
+/*
+ * SVM.NET Library
+ * Copyright (C) 2008 Matthew Johnson
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using System;
+using System.Collections.Generic;
+
+namespace SVM
+{
+    /// <summary>
+    /// Class containing the routines to train SVM models.
+    /// </summary>
+    public static class Training
+    {
+        /// <summary>
+        /// Whether the system will output information to the console during the training process.
+        /// </summary>
+        public static bool IsVerbose
+        {
+            get
+            {
+                return Procedures.IsVerbose;
+            }
+            set
+            {
+                Procedures.IsVerbose = value;
+            }
+        }
+
+        private static double doCrossValidation(Problem problem, Parameter parameters, int nr_fold)
+        {
+            int i;
+            double[] target = new double[problem.Count];
+            Procedures.svm_cross_validation(problem, parameters, nr_fold, target);
+            int total_correct = 0;
+            double total_error = 0;
+            double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
+            if (parameters.SvmType == SvmType.EPSILON_SVR || parameters.SvmType == SvmType.NU_SVR)
+            {
+                for (i = 0; i < problem.Count; i++)
+                {
+                    double y = problem.Y[i];
+                    double v = target[i];
+                    total_error += (v - y) * (v - y);
+                    sumv += v;
+                    sumy += y;
+                    sumvv += v * v;
+                    sumyy += y * y;
+                    sumvy += v * y;
+                }
+                return(problem.Count * sumvy - sumv * sumy) / (Math.Sqrt(problem.Count * sumvv - sumv * sumv) * Math.Sqrt(problem.Count * sumyy - sumy * sumy));
+            }
+            else
+                for (i = 0; i < problem.Count; i++)
+                    if (target[i] == problem.Y[i])
+                        ++total_correct;
+            return (double)total_correct / problem.Count;
+        }
+        /// <summary>
+        /// Legacy.  Allows use as if this was svm_train.  See libsvm documentation for details on which arguments to pass.
+        /// </summary>
+        /// <param name="args"></param>
+        [Obsolete("Provided only for legacy compatibility, use the other Train() methods")]
+        public static void Train(params string[] args)
+        {
+            Parameter parameters;
+            Problem problem;
+            bool crossValidation;
+            int nrfold;
+            string modelFilename;
+            parseCommandLine(args, out parameters, out problem, out crossValidation, out nrfold, out modelFilename);
+            if (crossValidation)
+                PerformCrossValidation(problem, parameters, nrfold);
+            else Model.Write(modelFilename, Train(problem, parameters));
+        }
+
+        /// <summary>
+        /// Performs cross validation.
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="parameters">The parameters to test</param>
+        /// <param name="nrfold">The number of cross validations to use</param>
+        /// <returns>The cross validation score</returns>
+        public static double PerformCrossValidation(Problem problem, Parameter parameters, int nrfold)
+        {
+            string error = Procedures.svm_check_parameter(problem, parameters);
+            if (error == null)
+                return doCrossValidation(problem, parameters, nrfold);
+            else throw new Exception(error);
+        }
+
+        /// <summary>
+        /// Trains a model using the provided training data and parameters.
+        /// </summary>
+        /// <param name="problem">The training data</param>
+        /// <param name="parameters">The parameters to use</param>
+        /// <returns>A trained SVM Model</returns>
+        public static Model Train(Problem problem, Parameter parameters)
+        {
+            string error = Procedures.svm_check_parameter(problem, parameters);
+
+            if (error == null)
+                return Procedures.svm_train(problem, parameters);
+            else throw new Exception(error);
+        }
+
+        private static void parseCommandLine(string[] args, out Parameter parameters, out Problem problem, out bool crossValidation, out int nrfold, out string modelFilename)
+        {
+            int i;
+
+            parameters = new Parameter();
+            // default values
+
+            crossValidation = false;
+            nrfold = 0;
+
+            // parse options
+            for (i = 0; i < args.Length; i++)
+            {
+                if (args[i][0] != '-')
+                    break;
+                ++i;
+                switch (args[i - 1][1])
+                {
+
+                    case 's':
+                        parameters.SvmType = (SvmType)int.Parse(args[i]);
+                        break;
+
+                    case 't':
+                        parameters.KernelType = (KernelType)int.Parse(args[i]);
+                        break;
+
+                    case 'd':
+                        parameters.Degree = int.Parse(args[i]);
+                        break;
+
+                    case 'g':
+                        parameters.Gamma = double.Parse(args[i]);
+                        break;
+
+                    case 'r':
+                        parameters.Coefficient0 = double.Parse(args[i]);
+                        break;
+
+                    case 'n':
+                        parameters.Nu = double.Parse(args[i]);
+                        break;
+
+                    case 'm':
+                        parameters.CacheSize = double.Parse(args[i]);
+                        break;
+
+                    case 'c':
+                        parameters.C = double.Parse(args[i]);
+                        break;
+
+                    case 'e':
+                        parameters.EPS = double.Parse(args[i]);
+                        break;
+
+                    case 'p':
+                        parameters.P = double.Parse(args[i]);
+                        break;
+
+                    case 'h':
+                        parameters.Shrinking = int.Parse(args[i]) == 1;
+                        break;
+
+                    case 'b':
+                        parameters.Probability = int.Parse(args[i]) == 1;
+                        break;
+
+                    case 'v':
+                        crossValidation = true;
+                        nrfold = int.Parse(args[i]);
+                        if (nrfold < 2)
+                        {
+                            throw new ArgumentException("n-fold cross validation: n must >= 2");
+                        }
+                        break;
+
+                    case 'w':
+                        parameters.Weights[int.Parse(args[i - 1].Substring(2))] = double.Parse(args[1]);
+                        break;
+
+                    default:
+                        throw new ArgumentException("Unknown Parameter");
+                }
+            }
+
+            // determine filenames
+
+            if (i >= args.Length)
+                throw new ArgumentException("No input file specified");
+
+            problem = Problem.Read(args[i]);
+
+            if (parameters.Gamma == 0)
+                parameters.Gamma = 1.0 / problem.MaxIndex;
+
+            if (i < args.Length - 1)
+                modelFilename = args[i + 1];
+            else
+            {
+                int p = args[i].LastIndexOf('/') + 1;
+                modelFilename = args[i].Substring(p) + ".model";
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/HeuristicLab.SQLServerCompact-3.5.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/HeuristicLab.SQLServerCompact-3.5.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/HeuristicLab.SQLServerCompact-3.5.csproj	(revision 2645)
@@ -0,0 +1,134 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{31DD6385-7276-49ED-9533-823D4CDF3D2A}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.SQLServerCompact</RootNamespace>
+    <AssemblyName>HeuristicLab.SQLServerCompact-3.5</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HeuristicLabSQLServerCompactPlugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="SQLServer Compact license.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="System.Data.SqlServerCe-3.5.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="x64\sqlceca35.dll" />
+    <Content Include="x64\sqlcecompact35.dll" />
+    <Content Include="x64\sqlceer35EN.dll" />
+    <Content Include="x64\sqlceme35.dll" />
+    <Content Include="x64\sqlceoledb35.dll" />
+    <Content Include="x64\sqlceqp35.dll" />
+    <Content Include="x64\sqlcese35.dll" />
+    <Content Include="x86\sqlceca35.dll" />
+    <Content Include="x86\sqlcecompact35.dll" />
+    <Content Include="x86\sqlceer35EN.dll" />
+    <Content Include="x86\sqlceme35.dll" />
+    <Content Include="x86\sqlceoledb35.dll" />
+    <Content Include="x86\sqlceqp35.dll" />
+    <Content Include="x86\sqlcese35.dll" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/HeuristicLabSQLServerCompactPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/HeuristicLabSQLServerCompactPlugin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/HeuristicLabSQLServerCompactPlugin.cs	(revision 2645)
@@ -0,0 +1,43 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.SQLServerCompact {
+  [Plugin("HeuristicLab.SQLServerCompact-3.5")]
+  [PluginFile("HeuristicLab.SQLServerCompact-3.5.dll", PluginFileType.Assembly)]
+  [PluginFile("System.Data.SqlServerCe-3.5.dll", PluginFileType.Assembly)]
+  [PluginFile("SQLServer Compact license.txt",PluginFileType.License)]
+  [PluginFile("sqlceca35.dll", PluginFileType.NativeDll)]
+  [PluginFile("sqlcecompact35.dll", PluginFileType.NativeDll)]
+  [PluginFile("sqlceer35EN.dll", PluginFileType.NativeDll)]
+  [PluginFile("sqlceme35.dll", PluginFileType.NativeDll)]
+  [PluginFile("sqlceoledb35.dll", PluginFileType.NativeDll)]
+  [PluginFile("sqlceqp35.dll", PluginFileType.NativeDll)]
+  [PluginFile("sqlcese35.dll", PluginFileType.NativeDll)] 
+  public class HeuristicLabSQLServerCompactPlugin : PluginBase {
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/Properties/AssemblyInfo.frame
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/Properties/AssemblyInfo.frame	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/Properties/AssemblyInfo.frame	(revision 2645)
@@ -0,0 +1,38 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.SQLServerCompact")]
+[assembly: AssemblyDescription("Provides an interface to create and access local SQLServer Compact databases")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3f5083f8-2738-4573-b230-e9928ef61e6b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("3.2.0.$WCREV$")]
+[assembly: AssemblyFileVersion("3.2.0.$WCREV$")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/SQLServer Compact license.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/SQLServer Compact license.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLServerCompact/3.5/SQLServer Compact license.txt	(revision 2645)
@@ -0,0 +1,52 @@
+MICROSOFT SOFTWARE LICENSE TERMS
+MICROSOFT SQL SERVER COMPACT 3.5
+These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you.  Please read them.  They apply to the software named above, which includes the media on which you received it, if any.  The terms also apply to any Microsoft
+	updates,
+	supplements,
+	Internet-based services, and 
+	support services
+for this software, unless other terms accompany those items.  If so, those terms apply.
+BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.  IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.
+If you comply with these license terms, you have the rights below.
+1.	INSTALLATION AND USE RIGHTS.  You may install and use any number of copies of the software on your devices.
+2.	ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.
+a.	Distributable Code.  The software contains code that you are permitted to distribute in programs you develop if you comply with the terms below.
+i.	Right to Use and Distribute.  The code and text files listed below are Distributable Code.
+	REDIST.TXT Files.  You may copy and distribute the object code form of code listed in REDIST.TXT files.
+	Third Party Distribution.  You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.
+ii.	Distribution Requirements.  For any Distributable Code you distribute, you must
+	add significant primary functionality to it in your programs;
+	require distributors and external end users to agree to terms that protect it at least as much as this agreement; 
+	display your valid copyright notice on your programs; and
+	indemnify, defend, and hold harmless Microsoft from any claims, including attorneys fees, related to the distribution or use of your programs.
+iii.	Distribution Restrictions.  You may not
+	alter any copyright, trademark or patent notice in the Distributable Code; 
+	use Microsofts trademarks in your programs names or in a way that suggests your programs come from or are endorsed by Microsoft; 
+	distribute Distributable Code to run on a platform other than the Windows platform;
+	include Distributable Code in malicious, deceptive or unlawful programs; or
+	modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License.  An Excluded License is one that requires, as a condition of use, modification or distribution, that
+	the code be disclosed or distributed in source code form; or 
+	others have the right to modify it.
+3.	SCOPE OF LICENSE.  The software is licensed, not sold. This agreement only gives you some rights to use the software.  Microsoft reserves all other rights.  Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement.  In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways.    You may not
+	work around any technical limitations in the software;
+	reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;
+	make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;
+	publish the software for others to copy;
+	rent, lease or lend the software; or
+	use the software for commercial software hosting services.
+4.	BACKUP COPY.  You may make one backup copy of the software.  You may use it only to reinstall the software.
+5.	DOCUMENTATION.  Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.
+6.	TRANSFER TO A THIRD PARTY.  The first user of the software may transfer it and this agreement directly to a third party.  Before the transfer, that party must agree that this agreement applies to the transfer and use of the software.  The first user must uninstall the software before transferring it separately from the device.  The first user may not retain any copies.
+7.	EXPORT RESTRICTIONS.  The software is subject to United States export laws and regulations.  You must comply with all domestic and international export laws and regulations that apply to the software.  These laws include restrictions on destinations, end users and end use.  For additional information, see www.microsoft.com/exporting.
+8.	SUPPORT SERVICES. Because this software is as is, we may not provide support services for it.
+9.	ENTIRE AGREEMENT.  This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.
+10.	APPLICABLE LAW.
+a.	United States.  If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles.  The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.
+b.	Outside the United States.  If you acquired the software in any other country, the laws of that country apply.
+11.	LEGAL EFFECT.  This agreement describes certain legal rights.  You may have other rights under the laws of your country.  You may also have rights with respect to the party from whom you acquired the software.  This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.
+12.	DISCLAIMER OF WARRANTY.   THE SOFTWARE IS LICENSED AS-IS.  YOU BEAR THE RISK OF USING IT.  MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS.  YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE.  TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+13.	LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES.  YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00.  YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
+This limitation applies to
+	anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and
+	claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.
+It also applies even if Microsoft knew or should have known about the possibility of the damages.  The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/HeuristicLab.SQLite-1.0.65.0.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/HeuristicLab.SQLite-1.0.65.0.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/HeuristicLab.SQLite-1.0.65.0.csproj	(revision 2645)
@@ -0,0 +1,124 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{6960CBCD-E44B-49B0-BA86-671091C42C36}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.SQLite</RootNamespace>
+    <AssemblyName>HeuristicLab.SQLite-1.0.65.0</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\HeuristicLab.SQLite-1.0.65.0.xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.SQLite-3.2.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\x64\Release\HeuristicLab.SQLite-1.0.65.0.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HeuristicLabSQLitePlugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="SQLite.NET.chm">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="SQLite License.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="x64\System.Data.SQLite.DLL" />
+    <Content Include="x86\System.Data.SQLite.DLL" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/HeuristicLab.SQLite-1.0.65.0.csproj.user
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/HeuristicLab.SQLite-1.0.65.0.csproj.user	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/HeuristicLab.SQLite-1.0.65.0.csproj.user	(revision 2645)
@@ -0,0 +1,5 @@
+﻿<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <ProjectView>ProjectFiles</ProjectView>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/Properties/AssemblyInfo.frame
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/Properties/AssemblyInfo.frame	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/Properties/AssemblyInfo.frame	(revision 2645)
@@ -0,0 +1,38 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.SQLite")]
+[assembly: AssemblyDescription("Provides an interface to create and access local SQLite databases")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3f5083f8-2738-4573-b230-e9928ef61e6b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.65.0")]
+[assembly: AssemblyFileVersion("1.0.65.0")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/SQLite License.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/SQLite License.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.SQLite/1.0.65.0/SQLite License.txt	(revision 2645)
@@ -0,0 +1,21 @@
+﻿SQLite Copyright
+
+All of the deliverable code in SQLite has been dedicated to the public domain by the authors. 
+All code authors, and representatives of the companies they work for, have signed affidavits 
+dedicating their contributions to the public domain and originals of those signed affidavits 
+are stored in a firesafe at the main offices of Hwaci. Anyone is free to copy, modify, publish, 
+use, compile, sell, or distribute the original SQLite code, either in source code form or as a 
+compiled binary, for any purpose, commercial or non-commercial, and by any means.
+
+The previous paragraph applies to the deliverable code in SQLite - those parts of the SQLite 
+library that you actually bundle and ship with a larger application. Portions of the documentation
+and some code used as part of the build process might fall under other licenses. The details 
+here are unclear. We do not worry about the licensing of the documentation and build code so 
+much because none of these things are part of the core deliverable SQLite library.
+
+All of the deliverable code in SQLite has been written from scratch. No code has been taken 
+from other projects or from the open internet. Every line of code can be traced back to its 
+original author, and all of those authors have public domain dedications on file. So the SQLite 
+code base is clean and is uncontaminated with licensed code from other projects. 
+
+(http://www.sqlite.org/copyright.html)
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/HeuristicLab.WinFormsUI-2.3.1.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/HeuristicLab.WinFormsUI-2.3.1.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/HeuristicLab.WinFormsUI-2.3.1.csproj	(revision 2645)
@@ -0,0 +1,120 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{678E2145-8152-4E19-9646-07D439D00301}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.WinFormsUI</RootNamespace>
+    <AssemblyName>HeuristicLab.WinFormsUI-2.3.1</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HeuristicLabWinFormsUIPlugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="WeifenLuo.WinFormsUI.Docking License.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\WinFormsUI-2.3.1\WinFormsUI-2.3.1.csproj">
+      <Project>{C75532C4-765B-418E-B09B-46D36B2ABDB1}</Project>
+      <Name>WinFormsUI-2.3.1</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/HeuristicLabWinFormsUIPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/HeuristicLabWinFormsUIPlugin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/HeuristicLabWinFormsUIPlugin.cs	(revision 2645)
@@ -0,0 +1,15 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.WinFormsUI {
+  [Plugin("HeuristicLab.WinFormsUI-2.3.1")]
+  [PluginFile("HeuristicLab.WinFormsUI-2.3.1.dll", PluginFileType.Assembly)]
+  [PluginFile("WeifenLuo.WinFormsUI.Docking-2.3.1.dll", PluginFileType.Assembly)]
+  [PluginFile("WeifenLuo.WinformsUI.Docking License.txt",PluginFileType.License)]
+  public class HeuristicLabWinFormsUIPlugin : PluginBase {
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/Properties/AssemblyInfo.frame
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/Properties/AssemblyInfo.frame	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/Properties/AssemblyInfo.frame	(revision 2645)
@@ -0,0 +1,38 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.WinFormsUI")]
+[assembly: AssemblyDescription("Provides docking abilities for WinForms applications")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3f5083f8-2738-4573-b230-e9928ef61e6b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("2.3.1")]
+[assembly: AssemblyFileVersion("2.3.1")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/WeifenLuo.WinFormsUI.Docking License.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/WeifenLuo.WinFormsUI.Docking License.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/HeuristicLab.WinFormsUI-2.3.1/WeifenLuo.WinFormsUI.Docking License.txt	(revision 2645)
@@ -0,0 +1,9 @@
+The MIT License
+
+Copyright (c) 2007 Weifen Luo (email: weifenluo@yahoo.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/AutoHideStripBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/AutoHideStripBase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/AutoHideStripBase.cs	(revision 2645)
@@ -0,0 +1,530 @@
+using System;
+using System.Collections;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public abstract partial class AutoHideStripBase : Control
+	{
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        protected class Tab : IDisposable
+        {
+            private IDockContent m_content;
+
+            protected internal Tab(IDockContent content)
+            {
+                m_content = content;
+            }
+
+            ~Tab()
+            {
+                Dispose(false);
+            }
+
+            public IDockContent Content
+            {
+                get { return m_content; }
+            }
+
+            public void Dispose()
+            {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
+
+            protected virtual void Dispose(bool disposing)
+            {
+            }
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        protected sealed class TabCollection : IEnumerable<Tab>
+        {
+            #region IEnumerable Members
+            IEnumerator<Tab> IEnumerable<Tab>.GetEnumerator()
+            {
+                for (int i = 0; i < Count; i++)
+                    yield return this[i];
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                for (int i = 0; i < Count; i++)
+                    yield return this[i];
+            }
+            #endregion
+
+            internal TabCollection(DockPane pane)
+            {
+                m_dockPane = pane;
+            }
+
+            private DockPane m_dockPane = null;
+            public DockPane DockPane
+            {
+                get { return m_dockPane; }
+            }
+
+            public DockPanel DockPanel
+            {
+                get { return DockPane.DockPanel; }
+            }
+
+            public int Count
+            {
+                get { return DockPane.DisplayingContents.Count; }
+            }
+
+            public Tab this[int index]
+            {
+                get
+                {
+                    IDockContent content = DockPane.DisplayingContents[index];
+                    if (content == null)
+                        throw (new ArgumentOutOfRangeException("index"));
+                    if (content.DockHandler.AutoHideTab == null)
+                        content.DockHandler.AutoHideTab = (DockPanel.AutoHideStripControl.CreateTab(content));
+                    return content.DockHandler.AutoHideTab as Tab;
+                }
+            }
+
+            public bool Contains(Tab tab)
+            {
+                return (IndexOf(tab) != -1);
+            }
+
+            public bool Contains(IDockContent content)
+            {
+                return (IndexOf(content) != -1);
+            }
+
+            public int IndexOf(Tab tab)
+            {
+                if (tab == null)
+                    return -1;
+
+                return IndexOf(tab.Content);
+            }
+
+            public int IndexOf(IDockContent content)
+            {
+                return DockPane.DisplayingContents.IndexOf(content);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        protected class Pane : IDisposable
+        {
+            private DockPane m_dockPane;
+
+            protected internal Pane(DockPane dockPane)
+            {
+                m_dockPane = dockPane;
+            }
+
+            ~Pane()
+            {
+                Dispose(false);
+            }
+
+            public DockPane DockPane
+            {
+                get { return m_dockPane; }
+            }
+
+            public TabCollection AutoHideTabs
+            {
+                get
+                {
+                    if (DockPane.AutoHideTabs == null)
+                        DockPane.AutoHideTabs = new TabCollection(DockPane);
+                    return DockPane.AutoHideTabs as TabCollection;
+                }
+            }
+
+            public void Dispose()
+            {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
+
+            protected virtual void Dispose(bool disposing)
+            {
+            }
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        protected sealed class PaneCollection : IEnumerable<Pane>
+        {
+            private class AutoHideState
+            {
+                public DockState m_dockState;
+                public bool m_selected = false;
+
+                public AutoHideState(DockState dockState)
+                {
+                    m_dockState = dockState;
+                }
+
+                public DockState DockState
+                {
+                    get { return m_dockState; }
+                }
+
+                public bool Selected
+                {
+                    get { return m_selected; }
+                    set { m_selected = value; }
+                }
+            }
+
+            private class AutoHideStateCollection
+            {
+                private AutoHideState[] m_states;
+
+                public AutoHideStateCollection()
+                {
+                    m_states = new AutoHideState[]	{	
+												new AutoHideState(DockState.DockTopAutoHide),
+												new AutoHideState(DockState.DockBottomAutoHide),
+												new AutoHideState(DockState.DockLeftAutoHide),
+												new AutoHideState(DockState.DockRightAutoHide)
+											};
+                }
+
+                public AutoHideState this[DockState dockState]
+                {
+                    get
+                    {
+                        for (int i = 0; i < m_states.Length; i++)
+                        {
+                            if (m_states[i].DockState == dockState)
+                                return m_states[i];
+                        }
+                        throw new ArgumentOutOfRangeException("dockState");
+                    }
+                }
+
+                public bool ContainsPane(DockPane pane)
+                {
+                    if (pane.IsHidden)
+                        return false;
+
+                    for (int i = 0; i < m_states.Length; i++)
+                    {
+                        if (m_states[i].DockState == pane.DockState && m_states[i].Selected)
+                            return true;
+                    }
+                    return false;
+                }
+            }
+
+            internal PaneCollection(DockPanel panel, DockState dockState)
+            {
+                m_dockPanel = panel;
+                m_states = new AutoHideStateCollection();
+                States[DockState.DockTopAutoHide].Selected = (dockState == DockState.DockTopAutoHide);
+                States[DockState.DockBottomAutoHide].Selected = (dockState == DockState.DockBottomAutoHide);
+                States[DockState.DockLeftAutoHide].Selected = (dockState == DockState.DockLeftAutoHide);
+                States[DockState.DockRightAutoHide].Selected = (dockState == DockState.DockRightAutoHide);
+            }
+
+            private DockPanel m_dockPanel;
+            public DockPanel DockPanel
+            {
+                get { return m_dockPanel; }
+            }
+
+            private AutoHideStateCollection m_states;
+            private AutoHideStateCollection States
+            {
+                get { return m_states; }
+            }
+
+            public int Count
+            {
+                get
+                {
+                    int count = 0;
+                    foreach (DockPane pane in DockPanel.Panes)
+                    {
+                        if (States.ContainsPane(pane))
+                            count++;
+                    }
+
+                    return count;
+                }
+            }
+
+            public Pane this[int index]
+            {
+                get
+                {
+                    int count = 0;
+                    foreach (DockPane pane in DockPanel.Panes)
+                    {
+                        if (!States.ContainsPane(pane))
+                            continue;
+
+                        if (count == index)
+                        {
+                            if (pane.AutoHidePane == null)
+                                pane.AutoHidePane = DockPanel.AutoHideStripControl.CreatePane(pane);
+                            return pane.AutoHidePane as Pane;
+                        }
+
+                        count++;
+                    }
+                    throw new ArgumentOutOfRangeException("index");
+                }
+            }
+
+            public bool Contains(Pane pane)
+            {
+                return (IndexOf(pane) != -1);
+            }
+
+            public int IndexOf(Pane pane)
+            {
+                if (pane == null)
+                    return -1;
+
+                int index = 0;
+                foreach (DockPane dockPane in DockPanel.Panes)
+                {
+                    if (!States.ContainsPane(pane.DockPane))
+                        continue;
+
+                    if (pane == dockPane.AutoHidePane)
+                        return index;
+
+                    index++;
+                }
+                return -1;
+            }
+
+            #region IEnumerable Members
+
+            IEnumerator<Pane> IEnumerable<Pane>.GetEnumerator()
+            {
+                for (int i = 0; i < Count; i++)
+                    yield return this[i];
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                for (int i = 0; i < Count; i++)
+                    yield return this[i];
+            }
+
+            #endregion
+        }
+
+		protected AutoHideStripBase(DockPanel panel)
+		{
+			m_dockPanel = panel;
+			m_panesTop = new PaneCollection(panel, DockState.DockTopAutoHide);
+			m_panesBottom = new PaneCollection(panel, DockState.DockBottomAutoHide);
+			m_panesLeft = new PaneCollection(panel, DockState.DockLeftAutoHide);
+			m_panesRight = new PaneCollection(panel, DockState.DockRightAutoHide);
+
+			SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+			SetStyle(ControlStyles.Selectable, false);
+		}
+
+		private DockPanel m_dockPanel;
+		protected DockPanel DockPanel
+		{
+			get	{	return m_dockPanel;	}
+		}
+
+		private PaneCollection m_panesTop;
+		protected PaneCollection PanesTop
+		{
+			get	{	return m_panesTop;	}
+		}
+
+		private PaneCollection m_panesBottom;
+		protected PaneCollection PanesBottom
+		{
+			get	{	return m_panesBottom;	}
+		}
+
+		private PaneCollection m_panesLeft;
+		protected PaneCollection PanesLeft
+		{
+			get	{	return m_panesLeft;	}
+		}
+
+		private PaneCollection m_panesRight;
+		protected PaneCollection PanesRight
+		{
+			get	{	return m_panesRight;	}
+		}
+
+		protected PaneCollection GetPanes(DockState dockState)
+		{
+			if (dockState == DockState.DockTopAutoHide)
+				return PanesTop;
+			else if (dockState == DockState.DockBottomAutoHide)
+				return PanesBottom;
+			else if (dockState == DockState.DockLeftAutoHide)
+				return PanesLeft;
+			else if (dockState == DockState.DockRightAutoHide)
+				return PanesRight;
+			else
+				throw new ArgumentOutOfRangeException("dockState");
+		}
+
+        internal int GetNumberOfPanes(DockState dockState)
+        {
+            return GetPanes(dockState).Count;
+        }
+
+		protected Rectangle RectangleTopLeft
+		{
+			get
+			{	
+				int height = MeasureHeight();
+				return PanesTop.Count > 0 && PanesLeft.Count > 0 ? new Rectangle(0, 0, height, height) : Rectangle.Empty;
+			}
+		}
+
+		protected Rectangle RectangleTopRight
+		{
+			get
+			{
+				int height = MeasureHeight();
+				return PanesTop.Count > 0 && PanesRight.Count > 0 ? new Rectangle(Width - height, 0, height, height) : Rectangle.Empty;
+			}
+		}
+
+		protected Rectangle RectangleBottomLeft
+		{
+			get
+			{
+				int height = MeasureHeight();
+				return PanesBottom.Count > 0 && PanesLeft.Count > 0 ? new Rectangle(0, Height - height, height, height) : Rectangle.Empty;
+			}
+		}
+
+		protected Rectangle RectangleBottomRight
+		{
+			get
+			{
+				int height = MeasureHeight();
+				return PanesBottom.Count > 0 && PanesRight.Count > 0 ? new Rectangle(Width - height, Height - height, height, height) : Rectangle.Empty;
+			}
+		}
+
+		protected internal Rectangle GetTabStripRectangle(DockState dockState)
+		{
+			int height = MeasureHeight();
+			if (dockState == DockState.DockTopAutoHide && PanesTop.Count > 0)
+				return new Rectangle(RectangleTopLeft.Width, 0, Width - RectangleTopLeft.Width - RectangleTopRight.Width, height);
+			else if (dockState == DockState.DockBottomAutoHide && PanesBottom.Count > 0)
+				return new Rectangle(RectangleBottomLeft.Width, Height - height, Width - RectangleBottomLeft.Width - RectangleBottomRight.Width, height);
+			else if (dockState == DockState.DockLeftAutoHide && PanesLeft.Count > 0)
+				return new Rectangle(0, RectangleTopLeft.Width, height, Height - RectangleTopLeft.Height - RectangleBottomLeft.Height);
+			else if (dockState == DockState.DockRightAutoHide && PanesRight.Count > 0)
+				return new Rectangle(Width - height, RectangleTopRight.Width, height, Height - RectangleTopRight.Height - RectangleBottomRight.Height);
+			else
+				return Rectangle.Empty;
+		}
+
+		private GraphicsPath m_displayingArea = null;
+		private GraphicsPath DisplayingArea
+		{
+			get
+			{
+				if (m_displayingArea == null)
+					m_displayingArea = new GraphicsPath();
+
+				return m_displayingArea;
+			}
+		}
+
+		private void SetRegion()
+		{
+			DisplayingArea.Reset();
+			DisplayingArea.AddRectangle(RectangleTopLeft);
+			DisplayingArea.AddRectangle(RectangleTopRight);
+			DisplayingArea.AddRectangle(RectangleBottomLeft);
+			DisplayingArea.AddRectangle(RectangleBottomRight);
+			DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockTopAutoHide));
+			DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockBottomAutoHide));
+			DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockLeftAutoHide));
+			DisplayingArea.AddRectangle(GetTabStripRectangle(DockState.DockRightAutoHide));
+			Region = new Region(DisplayingArea);
+		}
+
+		protected override void OnMouseDown(MouseEventArgs e)
+		{
+			base.OnMouseDown(e);
+
+			if (e.Button != MouseButtons.Left)
+				return;
+
+			IDockContent content = HitTest();
+			if (content == null)
+				return;
+
+			content.DockHandler.Activate();
+		}
+
+		protected override void OnMouseHover(EventArgs e)
+		{
+			base.OnMouseHover(e);
+
+			IDockContent content = HitTest();
+			if (content != null && DockPanel.ActiveAutoHideContent != content)
+				DockPanel.ActiveAutoHideContent = content;
+
+			// requires further tracking of mouse hover behavior,
+            ResetMouseEventArgs();
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+			RefreshChanges();
+			base.OnLayout (levent);
+		}
+
+		internal void RefreshChanges()
+		{
+            if (IsDisposed)
+                return;
+
+			SetRegion();
+			OnRefreshChanges();
+		}
+
+		protected virtual void OnRefreshChanges()
+		{
+		}
+
+		protected internal abstract int MeasureHeight();
+
+		private IDockContent HitTest()
+		{
+			Point ptMouse = PointToClient(Control.MousePosition);
+			return HitTest(ptMouse);
+		}
+
+        protected virtual Tab CreateTab(IDockContent content)
+        {
+            return new Tab(content);
+        }
+
+        protected virtual Pane CreatePane(DockPane dockPane)
+        {
+            return new Pane(dockPane);
+        }
+
+		protected abstract IDockContent HitTest(Point point);
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockAreasEditor.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockAreasEditor.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockAreasEditor.cs	(revision 2645)
@@ -0,0 +1,142 @@
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Design;
+using System.Windows.Forms;
+using System.Windows.Forms.Design;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{	
+	internal class DockAreasEditor : UITypeEditor
+	{
+		private class DockAreasEditorControl : System.Windows.Forms.UserControl
+		{
+			private CheckBox checkBoxFloat;
+			private CheckBox checkBoxDockLeft;
+			private CheckBox checkBoxDockRight;
+			private CheckBox checkBoxDockTop;
+			private CheckBox checkBoxDockBottom;
+			private CheckBox checkBoxDockFill;
+			private DockAreas m_oldDockAreas;
+
+			public DockAreas DockAreas
+			{
+				get
+				{
+					DockAreas dockAreas = 0;
+					if (checkBoxFloat.Checked)
+						dockAreas |= DockAreas.Float;
+					if (checkBoxDockLeft.Checked)
+						dockAreas |= DockAreas.DockLeft;
+					if (checkBoxDockRight.Checked)
+						dockAreas |= DockAreas.DockRight;
+					if (checkBoxDockTop.Checked)
+						dockAreas |= DockAreas.DockTop;
+					if (checkBoxDockBottom.Checked)
+						dockAreas |= DockAreas.DockBottom;
+					if (checkBoxDockFill.Checked)
+						dockAreas |= DockAreas.Document;
+
+					if (dockAreas == 0)
+						return m_oldDockAreas;
+					else
+						return dockAreas;
+				}
+			}
+
+			public DockAreasEditorControl()
+			{
+				checkBoxFloat = new CheckBox();
+				checkBoxDockLeft = new CheckBox();
+				checkBoxDockRight = new CheckBox();
+				checkBoxDockTop = new CheckBox();
+				checkBoxDockBottom = new CheckBox();
+				checkBoxDockFill = new CheckBox();
+
+				SuspendLayout();
+
+				checkBoxFloat.Appearance = Appearance.Button;
+				checkBoxFloat.Dock = DockStyle.Top;
+				checkBoxFloat.Height = 24;
+				checkBoxFloat.Text = Strings.DockAreaEditor_FloatCheckBoxText;
+				checkBoxFloat.TextAlign = ContentAlignment.MiddleCenter;
+				checkBoxFloat.FlatStyle = FlatStyle.System;
+			
+				checkBoxDockLeft.Appearance = System.Windows.Forms.Appearance.Button;
+				checkBoxDockLeft.Dock = System.Windows.Forms.DockStyle.Left;
+				checkBoxDockLeft.Width = 24;
+				checkBoxDockLeft.FlatStyle = FlatStyle.System;
+
+				checkBoxDockRight.Appearance = System.Windows.Forms.Appearance.Button;
+				checkBoxDockRight.Dock = System.Windows.Forms.DockStyle.Right;
+				checkBoxDockRight.Width = 24;
+				checkBoxDockRight.FlatStyle = FlatStyle.System;
+
+				checkBoxDockTop.Appearance = System.Windows.Forms.Appearance.Button;
+				checkBoxDockTop.Dock = System.Windows.Forms.DockStyle.Top;
+				checkBoxDockTop.Height = 24;
+				checkBoxDockTop.FlatStyle = FlatStyle.System;
+
+				checkBoxDockBottom.Appearance = System.Windows.Forms.Appearance.Button;
+				checkBoxDockBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
+				checkBoxDockBottom.Height = 24;
+				checkBoxDockBottom.FlatStyle = FlatStyle.System;
+			
+				checkBoxDockFill.Appearance = System.Windows.Forms.Appearance.Button;
+				checkBoxDockFill.Dock = System.Windows.Forms.DockStyle.Fill;
+				checkBoxDockFill.FlatStyle = FlatStyle.System;
+
+				this.Controls.AddRange(new Control[] {
+														 checkBoxDockFill,
+														 checkBoxDockBottom,
+														 checkBoxDockTop,
+														 checkBoxDockRight,
+														 checkBoxDockLeft,
+														 checkBoxFloat});
+
+				Size = new System.Drawing.Size(160, 144);
+				BackColor = SystemColors.Control;
+				ResumeLayout();
+			}
+
+			public void SetStates(DockAreas dockAreas)
+			{
+				m_oldDockAreas = dockAreas;
+				if ((dockAreas & DockAreas.DockLeft) != 0)
+					checkBoxDockLeft.Checked = true;
+				if ((dockAreas & DockAreas.DockRight) != 0)
+					checkBoxDockRight.Checked = true;
+				if ((dockAreas & DockAreas.DockTop) != 0)
+					checkBoxDockTop.Checked = true;
+				if ((dockAreas & DockAreas.DockTop) != 0)
+					checkBoxDockTop.Checked = true;
+				if ((dockAreas & DockAreas.DockBottom) != 0)
+					checkBoxDockBottom.Checked = true;
+				if ((dockAreas & DockAreas.Document) != 0)
+					checkBoxDockFill.Checked = true;
+				if ((dockAreas & DockAreas.Float) != 0)
+					checkBoxFloat.Checked = true;
+			}
+		}
+
+		private DockAreasEditor.DockAreasEditorControl m_ui = null;
+
+		public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
+		{
+			return UITypeEditorEditStyle.DropDown;
+		}
+
+		public override object EditValue(ITypeDescriptorContext context, IServiceProvider sp, object value)
+		{
+			if (m_ui == null)
+				m_ui = new DockAreasEditor.DockAreasEditorControl();
+
+			m_ui.SetStates((DockAreas)value);
+
+            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)sp.GetService(typeof(IWindowsFormsEditorService));
+			edSvc.DropDownControl(m_ui);
+
+			return m_ui.DockAreas;
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContent.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContent.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContent.cs	(revision 2645)
@@ -0,0 +1,304 @@
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public class DockContent : Form, IDockContent
+	{
+		public DockContent()
+		{
+			m_dockHandler = new DockContentHandler(this, new GetPersistStringCallback(GetPersistString));
+			m_dockHandler.DockStateChanged += new EventHandler(DockHandler_DockStateChanged);
+			//Suggested as a fix by bensty regarding form resize
+            this.ParentChanged += new EventHandler(DockContent_ParentChanged);
+		}
+
+		//Suggested as a fix by bensty regarding form resize
+        private void DockContent_ParentChanged(object Sender, EventArgs e)
+        {
+            if (this.Parent != null)
+                this.Font = this.Parent.Font;
+		}
+
+		private DockContentHandler m_dockHandler = null;
+		[Browsable(false)]
+		public DockContentHandler DockHandler
+		{
+			get	{	return m_dockHandler;	}
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_AllowEndUserDocking_Description")]
+		[DefaultValue(true)]
+		public bool AllowEndUserDocking
+		{
+			get	{	return DockHandler.AllowEndUserDocking;	}
+			set	{	DockHandler.AllowEndUserDocking = value;	}
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_DockAreas_Description")]
+		[DefaultValue(DockAreas.DockLeft|DockAreas.DockRight|DockAreas.DockTop|DockAreas.DockBottom|DockAreas.Document|DockAreas.Float)]
+		public DockAreas DockAreas
+		{
+			get	{	return DockHandler.DockAreas;	}
+			set	{	DockHandler.DockAreas = value;	}
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_AutoHidePortion_Description")]
+		[DefaultValue(0.25)]
+		public double AutoHidePortion
+		{
+			get	{	return DockHandler.AutoHidePortion;	}
+			set	{	DockHandler.AutoHidePortion = value;	}
+		}
+
+		[Localizable(true)]
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_TabText_Description")]
+		[DefaultValue(null)]
+        private string m_tabText = null;
+		public string TabText
+		{
+            get { return m_tabText; }
+            set { DockHandler.TabText = m_tabText = value; }
+		}
+		private bool ShouldSerializeTabText()
+		{
+			return (m_tabText != null);
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_CloseButton_Description")]
+		[DefaultValue(true)]
+		public bool CloseButton
+		{
+			get	{	return DockHandler.CloseButton;	}
+			set	{	DockHandler.CloseButton = value;	}
+		}
+
+        [LocalizedCategory("Category_Docking")]
+        [LocalizedDescription("DockContent_CloseButtonVisible_Description")]
+        [DefaultValue(true)]
+        public bool CloseButtonVisible
+        {
+            get { return DockHandler.CloseButtonVisible; }
+            set { DockHandler.CloseButtonVisible = value; }
+        }
+		
+		[Browsable(false)]
+		public DockPanel DockPanel
+		{
+			get {	return DockHandler.DockPanel; }
+			set	{	DockHandler.DockPanel = value;	}
+		}
+
+		[Browsable(false)]
+		public DockState DockState
+		{
+			get	{	return DockHandler.DockState;	}
+			set	{	DockHandler.DockState = value;	}
+		}
+
+		[Browsable(false)]
+		public DockPane Pane
+		{
+			get {	return DockHandler.Pane; }
+			set	{	DockHandler.Pane = value;		}
+		}
+
+		[Browsable(false)]
+		public bool IsHidden
+		{
+			get	{	return DockHandler.IsHidden;	}
+			set	{	DockHandler.IsHidden = value;	}
+		}
+
+		[Browsable(false)]
+		public DockState VisibleState
+		{
+			get	{	return DockHandler.VisibleState;	}
+			set	{	DockHandler.VisibleState = value;	}
+		}
+
+		[Browsable(false)]
+		public bool IsFloat
+		{
+			get	{	return DockHandler.IsFloat;	}
+			set	{	DockHandler.IsFloat = value;	}
+		}
+
+		[Browsable(false)]
+		public DockPane PanelPane
+		{
+			get	{	return DockHandler.PanelPane;	}
+			set	{	DockHandler.PanelPane = value;	}
+		}
+
+		[Browsable(false)]
+		public DockPane FloatPane
+		{
+			get	{	return DockHandler.FloatPane;	}
+			set	{	DockHandler.FloatPane = value;	}
+		}
+
+        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
+        protected virtual string GetPersistString()
+		{
+            return GetType().ToString();
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_HideOnClose_Description")]
+		[DefaultValue(false)]
+		public bool HideOnClose
+		{
+			get	{	return DockHandler.HideOnClose;	}
+			set	{	DockHandler.HideOnClose = value;	}
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_ShowHint_Description")]
+		[DefaultValue(DockState.Unknown)]
+		public DockState ShowHint
+		{
+			get	{	return DockHandler.ShowHint;	}
+			set	{	DockHandler.ShowHint = value;	}
+		}
+
+		[Browsable(false)]
+		public bool IsActivated
+		{
+			get	{	return DockHandler.IsActivated;	}
+		}
+
+		public bool IsDockStateValid(DockState dockState)
+		{
+			return DockHandler.IsDockStateValid(dockState);
+		}
+
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockContent_TabPageContextMenu_Description")]
+		[DefaultValue(null)]
+		public ContextMenu TabPageContextMenu
+		{
+			get	{	return DockHandler.TabPageContextMenu;	}
+			set	{	DockHandler.TabPageContextMenu = value;	}
+		}
+
+        [LocalizedCategory("Category_Docking")]
+        [LocalizedDescription("DockContent_TabPageContextMenuStrip_Description")]
+        [DefaultValue(null)]
+        public ContextMenuStrip TabPageContextMenuStrip
+        {
+            get { return DockHandler.TabPageContextMenuStrip; }
+            set { DockHandler.TabPageContextMenuStrip = value; }
+        }
+
+		[Localizable(true)]
+		[Category("Appearance")]
+		[LocalizedDescription("DockContent_ToolTipText_Description")]
+		[DefaultValue(null)]
+		public string ToolTipText
+		{
+			get	{	return DockHandler.ToolTipText;	}
+			set {	DockHandler.ToolTipText = value;	}
+		}
+
+		public new void Activate()
+		{
+			DockHandler.Activate();
+		}
+
+		public new void Hide()
+		{
+			DockHandler.Hide();
+		}
+
+		public new void Show()
+		{
+			DockHandler.Show();
+		}
+
+		public void Show(DockPanel dockPanel)
+		{
+			DockHandler.Show(dockPanel);
+		}
+
+		public void Show(DockPanel dockPanel, DockState dockState)
+		{
+			DockHandler.Show(dockPanel, dockState);
+		}
+
+        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")]
+		public void Show(DockPanel dockPanel, Rectangle floatWindowBounds)
+		{
+			DockHandler.Show(dockPanel, floatWindowBounds);
+		}
+
+		public void Show(DockPane pane, IDockContent beforeContent)
+		{
+			DockHandler.Show(pane, beforeContent);
+		}
+
+		public void Show(DockPane previousPane, DockAlignment alignment, double proportion)
+		{
+			DockHandler.Show(previousPane, alignment, proportion);
+		}
+
+        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")]
+        public void FloatAt(Rectangle floatWindowBounds)
+        {
+            DockHandler.FloatAt(floatWindowBounds);
+        }
+
+        public void DockTo(DockPane paneTo, DockStyle dockStyle, int contentIndex)
+        {
+            DockHandler.DockTo(paneTo, dockStyle, contentIndex);
+        }
+
+        public void DockTo(DockPanel panel, DockStyle dockStyle)
+        {
+            DockHandler.DockTo(panel, dockStyle);
+        }
+
+		#region IDockContent Members
+		void IDockContent.OnActivated(EventArgs e)
+		{
+			this.OnActivated(e);
+		}
+
+		void IDockContent.OnDeactivate(EventArgs e)
+		{
+			this.OnDeactivate(e);
+		}
+		#endregion
+
+		#region Events
+		private void DockHandler_DockStateChanged(object sender, EventArgs e)
+		{
+			OnDockStateChanged(e);
+		}
+
+		private static readonly object DockStateChangedEvent = new object();
+		[LocalizedCategory("Category_PropertyChanged")]
+		[LocalizedDescription("Pane_DockStateChanged_Description")]
+		public event EventHandler DockStateChanged
+		{
+			add	{	Events.AddHandler(DockStateChangedEvent, value);	}
+			remove	{	Events.RemoveHandler(DockStateChangedEvent, value);	}
+		}
+		protected virtual void OnDockStateChanged(EventArgs e)
+		{
+			EventHandler handler = (EventHandler)Events[DockStateChangedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+		#endregion
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentCollection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentCollection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentCollection.cs	(revision 2645)
@@ -0,0 +1,175 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    public class DockContentCollection : ReadOnlyCollection<IDockContent>
+    {
+        private static List<IDockContent> _emptyList = new List<IDockContent>(0);
+
+        internal DockContentCollection()
+            : base(new List<IDockContent>())
+        {
+        }
+
+        internal DockContentCollection(DockPane pane)
+            : base(_emptyList)
+        {
+            m_dockPane = pane;
+        }
+
+        private DockPane m_dockPane = null;
+        private DockPane DockPane
+        {
+            get { return m_dockPane; }
+        }
+
+        public new IDockContent this[int index]
+        {
+            get
+            {
+                if (DockPane == null)
+                    return Items[index] as IDockContent;
+                else
+                    return GetVisibleContent(index);
+            }
+        }
+
+        internal int Add(IDockContent content)
+        {
+#if DEBUG
+			if (DockPane != null)
+				throw new InvalidOperationException();
+#endif
+
+            if (Contains(content))
+                return IndexOf(content);
+
+            Items.Add(content);
+            return Count - 1;
+        }
+
+        internal void AddAt(IDockContent content, int index)
+        {
+#if DEBUG
+			if (DockPane != null)
+				throw new InvalidOperationException();
+#endif
+
+            if (index < 0 || index > Items.Count - 1)
+                return;
+
+            if (Contains(content))
+                return;
+
+            Items.Insert(index, content);
+        }
+
+        public new bool Contains(IDockContent content)
+        {
+            if (DockPane == null)
+                return Items.Contains(content);
+            else
+                return (GetIndexOfVisibleContents(content) != -1);
+        }
+
+        public new int Count
+        {
+            get
+            {
+                if (DockPane == null)
+                    return base.Count;
+                else
+                    return CountOfVisibleContents;
+            }
+        }
+
+        public new int IndexOf(IDockContent content)
+        {
+            if (DockPane == null)
+            {
+                if (!Contains(content))
+                    return -1;
+                else
+                    return Items.IndexOf(content);
+            }
+            else
+                return GetIndexOfVisibleContents(content);
+        }
+
+        internal void Remove(IDockContent content)
+        {
+            if (DockPane != null)
+                throw new InvalidOperationException();
+
+            if (!Contains(content))
+                return;
+
+            Items.Remove(content);
+        }
+
+        private int CountOfVisibleContents
+        {
+            get
+            {
+#if DEBUG
+				if (DockPane == null)
+					throw new InvalidOperationException();
+#endif
+
+                int count = 0;
+                foreach (IDockContent content in DockPane.Contents)
+                {
+                    if (content.DockHandler.DockState == DockPane.DockState)
+                        count++;
+                }
+                return count;
+            }
+        }
+
+        private IDockContent GetVisibleContent(int index)
+        {
+#if DEBUG
+			if (DockPane == null)
+				throw new InvalidOperationException();
+#endif
+
+            int currentIndex = -1;
+            foreach (IDockContent content in DockPane.Contents)
+            {
+                if (content.DockHandler.DockState == DockPane.DockState)
+                    currentIndex++;
+
+                if (currentIndex == index)
+                    return content;
+            }
+            throw (new ArgumentOutOfRangeException());
+        }
+
+        private int GetIndexOfVisibleContents(IDockContent content)
+        {
+#if DEBUG
+			if (DockPane == null)
+				throw new InvalidOperationException();
+#endif
+
+            if (content == null)
+                return -1;
+
+            int index = -1;
+            foreach (IDockContent c in DockPane.Contents)
+            {
+                if (c.DockHandler.DockState == DockPane.DockState)
+                {
+                    index++;
+
+                    if (c == content)
+                        return index;
+                }
+            }
+            return -1;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentEventArgs.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentEventArgs.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentEventArgs.cs	(revision 2645)
@@ -0,0 +1,19 @@
+using System;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public class DockContentEventArgs : EventArgs
+	{
+		private IDockContent m_content;
+
+		public DockContentEventArgs(IDockContent content)
+		{
+			m_content = content;
+		}
+
+		public IDockContent Content
+		{
+			get	{	return m_content;	}
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentHandler.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentHandler.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockContentHandler.cs	(revision 2645)
@@ -0,0 +1,1063 @@
+using System;
+using System.Windows.Forms;
+using System.Drawing;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public delegate string GetPersistStringCallback();
+
+	public class DockContentHandler : IDisposable, IDockDragSource
+	{
+		public DockContentHandler(Form form) : this(form, null)
+		{
+		}
+
+		public DockContentHandler(Form form, GetPersistStringCallback getPersistStringCallback)
+		{
+			if (!(form is IDockContent))
+				throw new ArgumentException(Strings.DockContent_Constructor_InvalidForm, "form");
+
+			m_form = form;
+			m_getPersistStringCallback = getPersistStringCallback;
+
+			m_events = new EventHandlerList();
+			Form.Disposed +=new EventHandler(Form_Disposed);
+			Form.TextChanged += new EventHandler(Form_TextChanged);
+		}
+
+		public void Dispose()
+		{
+			Dispose(true);
+			GC.SuppressFinalize(this);
+		}
+
+		protected virtual void Dispose(bool disposing)
+		{
+			if(disposing)
+			{
+				lock(this)
+				{
+					DockPanel = null;
+					if (m_autoHideTab != null)
+						m_autoHideTab.Dispose();
+					if (m_tab != null)
+						m_tab.Dispose();
+
+					Form.Disposed -= new EventHandler(Form_Disposed);
+					Form.TextChanged -= new EventHandler(Form_TextChanged);
+					m_events.Dispose();
+				}
+			}
+		}
+
+		private Form m_form;
+		public Form Form
+		{
+			get	{	return m_form;	}
+		}
+
+		public IDockContent Content
+		{
+			get	{	return Form as IDockContent;	}
+		}
+
+        private IDockContent m_previousActive = null;
+        public IDockContent PreviousActive
+        {
+            get { return m_previousActive; }
+            internal set { m_previousActive = value; }
+        }
+
+        private IDockContent m_nextActive = null;
+        public IDockContent NextActive
+        {
+            get { return m_nextActive; }
+            internal set { m_nextActive = value; }
+        }
+
+		private EventHandlerList m_events;
+		private EventHandlerList Events
+		{
+			get	{	return m_events;	}
+		}
+
+		private bool m_allowEndUserDocking = true;
+		public bool AllowEndUserDocking
+		{
+			get	{	return m_allowEndUserDocking;	}
+			set	{	m_allowEndUserDocking = value;	}
+		}
+
+		private double m_autoHidePortion = 0.25;
+		public double AutoHidePortion
+		{
+			get	{	return m_autoHidePortion;	}
+			set
+			{
+				if (value <= 0)
+					throw(new ArgumentOutOfRangeException(Strings.DockContentHandler_AutoHidePortion_OutOfRange));
+
+				if (m_autoHidePortion == value)
+					return;
+
+				m_autoHidePortion = value;
+
+				if (DockPanel == null)
+					return;
+
+				if (DockPanel.ActiveAutoHideContent == Content)
+					DockPanel.PerformLayout();
+			}
+		}
+
+		private bool m_closeButton = true;
+		public bool CloseButton
+		{
+			get	{	return m_closeButton;	}
+			set
+			{
+				if (m_closeButton == value)
+					return;
+
+				m_closeButton = value;
+				if (Pane != null)
+					if (Pane.ActiveContent.DockHandler == this)
+						Pane.RefreshChanges();
+			}
+		}
+
+        private bool m_closeButtonVisible = true;
+        /// <summary>
+        /// Determines whether the close button is visible on the content
+        /// </summary>
+        public bool CloseButtonVisible
+        {
+            get { return m_closeButtonVisible; }
+            set { m_closeButtonVisible = value; }
+        }
+		
+		private DockState DefaultDockState
+		{
+			get
+			{
+				if (ShowHint != DockState.Unknown && ShowHint != DockState.Hidden)
+					return ShowHint;
+
+				if ((DockAreas & DockAreas.Document) != 0)
+					return DockState.Document;
+				if ((DockAreas & DockAreas.DockRight) != 0)
+					return DockState.DockRight;
+				if ((DockAreas & DockAreas.DockLeft) != 0)
+					return DockState.DockLeft;
+				if ((DockAreas & DockAreas.DockBottom) != 0)
+					return DockState.DockBottom;
+				if ((DockAreas & DockAreas.DockTop) != 0)
+					return DockState.DockTop;
+
+				return DockState.Unknown;
+			}
+		}
+
+		private DockState DefaultShowState
+		{
+			get
+			{
+				if (ShowHint != DockState.Unknown)
+					return ShowHint;
+
+				if ((DockAreas & DockAreas.Document) != 0)
+					return DockState.Document;
+				if ((DockAreas & DockAreas.DockRight) != 0)
+					return DockState.DockRight;
+				if ((DockAreas & DockAreas.DockLeft) != 0)
+					return DockState.DockLeft;
+				if ((DockAreas & DockAreas.DockBottom) != 0)
+					return DockState.DockBottom;
+				if ((DockAreas & DockAreas.DockTop) != 0)
+					return DockState.DockTop;
+				if ((DockAreas & DockAreas.Float) != 0)
+					return DockState.Float;
+
+				return DockState.Unknown;
+			}
+		}
+
+		private DockAreas m_allowedAreas = DockAreas.DockLeft | DockAreas.DockRight | DockAreas.DockTop | DockAreas.DockBottom | DockAreas.Document | DockAreas.Float;
+		public DockAreas DockAreas
+		{
+			get	{	return m_allowedAreas;	}
+			set
+			{
+				if (m_allowedAreas == value)
+					return;
+
+				if (!DockHelper.IsDockStateValid(DockState, value))
+					throw(new InvalidOperationException(Strings.DockContentHandler_DockAreas_InvalidValue));
+
+				m_allowedAreas = value;
+
+				if (!DockHelper.IsDockStateValid(ShowHint, m_allowedAreas))
+					ShowHint = DockState.Unknown;
+			}
+		}
+
+		private DockState m_dockState = DockState.Unknown;
+		public DockState DockState
+		{
+			get	{	return m_dockState;	}
+			set
+			{
+				if (m_dockState == value)
+					return;
+
+                DockPanel.SuspendLayout(true);
+
+				if (value == DockState.Hidden)
+					IsHidden = true;
+				else
+					SetDockState(false, value, Pane);
+
+                DockPanel.ResumeLayout(true, true);
+			}
+		}
+
+		private DockPanel m_dockPanel = null;
+		public DockPanel DockPanel
+		{
+			get { return m_dockPanel; }
+			set
+			{
+				if (m_dockPanel == value)
+					return;
+
+				Pane = null;
+
+				if (m_dockPanel != null)
+					m_dockPanel.RemoveContent(Content);
+
+				if (m_tab != null)
+				{
+					m_tab.Dispose();
+					m_tab = null;
+				}
+
+				if (m_autoHideTab != null)
+				{
+					m_autoHideTab.Dispose();
+					m_autoHideTab = null;
+				}
+
+				m_dockPanel = value;
+
+				if (m_dockPanel != null)
+				{
+					m_dockPanel.AddContent(Content);
+					Form.TopLevel = false;
+					Form.FormBorderStyle = FormBorderStyle.None;
+					Form.ShowInTaskbar = false;
+                    Form.WindowState = FormWindowState.Normal;
+					NativeMethods.SetWindowPos(Form.Handle, IntPtr.Zero, 0, 0, 0, 0,
+						Win32.FlagsSetWindowPos.SWP_NOACTIVATE |
+						Win32.FlagsSetWindowPos.SWP_NOMOVE |
+						Win32.FlagsSetWindowPos.SWP_NOSIZE |
+						Win32.FlagsSetWindowPos.SWP_NOZORDER |
+						Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER |
+						Win32.FlagsSetWindowPos.SWP_FRAMECHANGED);
+				}
+			}
+		}
+
+		public Icon Icon
+		{
+			get	{	return Form.Icon;	}
+		}
+
+		public DockPane Pane
+		{
+			get {	return IsFloat ? FloatPane : PanelPane; }
+			set
+			{
+				if (Pane == value)
+					return;
+
+                DockPanel.SuspendLayout(true);
+
+				DockPane oldPane = Pane;
+
+				SuspendSetDockState();
+				FloatPane = (value == null ? null : (value.IsFloat ? value : FloatPane));
+				PanelPane = (value == null ? null : (value.IsFloat ? PanelPane : value));
+				ResumeSetDockState(IsHidden, value != null ? value.DockState : DockState.Unknown, oldPane);
+
+                DockPanel.ResumeLayout(true, true);
+			}
+		}
+
+		private bool m_isHidden = true;
+		public bool IsHidden
+		{
+			get	{	return m_isHidden;	}
+			set
+			{
+				if (m_isHidden == value)
+					return;
+
+				SetDockState(value, VisibleState, Pane);
+			}
+		}
+
+		private string m_tabText = null;
+		public string TabText
+		{
+            get { return m_tabText == null || m_tabText == "" ? Form.Text : m_tabText; }
+			set
+			{
+				if (m_tabText == value)
+					return;
+
+				m_tabText = value;
+				if (Pane != null)
+					Pane.RefreshChanges();
+			}
+		}
+
+		private DockState m_visibleState = DockState.Unknown;
+		public DockState VisibleState
+		{
+			get	{	return m_visibleState;	}
+			set
+			{
+				if (m_visibleState == value)
+					return;
+
+				SetDockState(IsHidden, value, Pane);
+			}
+		}
+
+		private bool m_isFloat = false;
+		public bool IsFloat
+		{
+			get	{	return m_isFloat;	}
+			set
+			{
+				if (m_isFloat == value)
+					return;
+
+                DockState visibleState = CheckDockState(value);
+
+				if (visibleState == DockState.Unknown)
+					throw new InvalidOperationException(Strings.DockContentHandler_IsFloat_InvalidValue);
+
+				SetDockState(IsHidden, visibleState, Pane);
+			}
+		}
+
+        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")]
+        public DockState CheckDockState(bool isFloat)
+        {
+            DockState dockState;
+
+            if (isFloat)
+            {
+                if (!IsDockStateValid(DockState.Float))
+                    dockState = DockState.Unknown;
+                else
+                    dockState = DockState.Float;
+            }
+            else
+            {
+                dockState = (PanelPane != null) ? PanelPane.DockState : DefaultDockState;
+                if (dockState != DockState.Unknown && !IsDockStateValid(dockState))
+                    dockState = DockState.Unknown;
+            }
+
+            return dockState;
+        }
+
+		private DockPane m_panelPane = null;
+		public DockPane PanelPane
+		{
+			get	{	return m_panelPane;	}
+			set
+			{
+				if (m_panelPane == value)
+					return;
+
+				if (value != null)
+				{
+					if (value.IsFloat || value.DockPanel != DockPanel)
+						throw new InvalidOperationException(Strings.DockContentHandler_DockPane_InvalidValue);
+				}
+
+				DockPane oldPane = Pane;
+
+                if (m_panelPane != null)
+                    RemoveFromPane(m_panelPane);
+				m_panelPane = value;
+				if (m_panelPane != null)
+				{
+					m_panelPane.AddContent(Content);
+					SetDockState(IsHidden, IsFloat ? DockState.Float : m_panelPane.DockState, oldPane);
+				}
+				else
+					SetDockState(IsHidden, DockState.Unknown, oldPane);
+			}
+		}
+
+        private void RemoveFromPane(DockPane pane)
+        {
+            pane.RemoveContent(Content);
+            SetPane(null);
+            if (pane.Contents.Count == 0)
+                pane.Dispose();
+        }
+
+		private DockPane m_floatPane = null;
+		public DockPane FloatPane
+		{
+			get	{	return m_floatPane;	}
+			set
+			{
+				if (m_floatPane == value)
+					return;
+
+				if (value != null)
+				{
+					if (!value.IsFloat || value.DockPanel != DockPanel)
+						throw new InvalidOperationException(Strings.DockContentHandler_FloatPane_InvalidValue);
+				}
+
+				DockPane oldPane = Pane;
+
+                if (m_floatPane != null)
+                    RemoveFromPane(m_floatPane);
+				m_floatPane = value;
+				if (m_floatPane != null)
+				{
+					m_floatPane.AddContent(Content);
+					SetDockState(IsHidden, IsFloat ? DockState.Float : VisibleState, oldPane);
+				}
+				else
+					SetDockState(IsHidden, DockState.Unknown, oldPane);
+			}
+		}
+
+		private int m_countSetDockState = 0;
+		private void SuspendSetDockState()
+		{
+			m_countSetDockState ++;
+		}
+
+		private void ResumeSetDockState()
+		{
+			m_countSetDockState --;
+			if (m_countSetDockState < 0)
+				m_countSetDockState = 0;
+		}
+
+		internal bool IsSuspendSetDockState
+		{
+			get	{	return m_countSetDockState != 0;	}
+		}
+
+		private void ResumeSetDockState(bool isHidden, DockState visibleState, DockPane oldPane)
+		{
+			ResumeSetDockState();
+			SetDockState(isHidden, visibleState, oldPane);
+		}
+
+		internal void SetDockState(bool isHidden, DockState visibleState, DockPane oldPane)
+		{
+			if (IsSuspendSetDockState)
+				return;
+
+			if (DockPanel == null && visibleState != DockState.Unknown)
+				throw new InvalidOperationException(Strings.DockContentHandler_SetDockState_NullPanel);
+
+			if (visibleState == DockState.Hidden || (visibleState != DockState.Unknown && !IsDockStateValid(visibleState)))
+				throw new InvalidOperationException(Strings.DockContentHandler_SetDockState_InvalidState);
+
+            DockPanel dockPanel = DockPanel;
+            if (dockPanel != null)
+                dockPanel.SuspendLayout(true);
+
+			SuspendSetDockState();
+
+			DockState oldDockState = DockState;
+
+			if (m_isHidden != isHidden || oldDockState == DockState.Unknown)
+			{
+				m_isHidden = isHidden;
+			}
+			m_visibleState = visibleState;
+			m_dockState = isHidden ? DockState.Hidden : visibleState;
+
+            if (visibleState == DockState.Unknown)
+                Pane = null;
+            else
+            {
+                m_isFloat = (m_visibleState == DockState.Float);
+
+                if (Pane == null)
+                    Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, visibleState, true);
+                else if (Pane.DockState != visibleState)
+                {
+                    if (Pane.Contents.Count == 1)
+                        Pane.SetDockState(visibleState);
+                    else
+                        Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, visibleState, true);
+                }
+            }
+
+            if (Form.ContainsFocus)
+                if (DockState == DockState.Hidden || DockState == DockState.Unknown)
+                    DockPanel.ContentFocusManager.GiveUpFocus(Content);
+
+            SetPaneAndVisible(Pane);
+
+			if (oldPane != null && !oldPane.IsDisposed && oldDockState == oldPane.DockState)
+				RefreshDockPane(oldPane);
+
+			if (Pane != null && DockState == Pane.DockState)
+			{
+				if ((Pane != oldPane) ||
+					(Pane == oldPane && oldDockState != oldPane.DockState))
+					// Avoid early refresh of hidden AutoHide panes
+					if ((Pane.DockWindow == null || Pane.DockWindow.Visible || Pane.IsHidden) && !Pane.IsAutoHide)
+						RefreshDockPane(Pane);			
+			}
+
+            if (oldDockState != DockState)
+            {
+                if (DockState == DockState.Hidden || DockState == DockState.Unknown ||
+                    DockHelper.IsDockStateAutoHide(DockState))
+                    DockPanel.ContentFocusManager.RemoveFromList(Content);
+                else
+                    DockPanel.ContentFocusManager.AddToList(Content);
+
+                OnDockStateChanged(EventArgs.Empty);
+            }
+			ResumeSetDockState();
+
+            if (dockPanel != null)
+                dockPanel.ResumeLayout(true, true);
+		}
+
+		private static void RefreshDockPane(DockPane pane)
+		{
+			pane.RefreshChanges();
+			pane.ValidateActiveContent();
+		}
+
+		internal string PersistString
+		{
+			get	{	return GetPersistStringCallback == null ? Form.GetType().ToString() : GetPersistStringCallback();	}
+		}
+
+		private GetPersistStringCallback m_getPersistStringCallback = null;
+		public GetPersistStringCallback GetPersistStringCallback
+		{
+			get	{	return m_getPersistStringCallback;	}
+			set	{	m_getPersistStringCallback = value;	}
+		}
+
+
+		private bool m_hideOnClose = false;
+		public bool HideOnClose
+		{
+			get	{	return m_hideOnClose;	}
+			set	{	m_hideOnClose = value;	}
+		}
+
+		private DockState m_showHint = DockState.Unknown;
+		public DockState ShowHint
+		{
+			get	{	return m_showHint;	}
+			set
+			{	
+				if (!DockHelper.IsDockStateValid(value, DockAreas))
+					throw (new InvalidOperationException(Strings.DockContentHandler_ShowHint_InvalidValue));
+
+				if (m_showHint == value)
+					return;
+
+				m_showHint = value;
+			}
+		}
+
+		private bool m_isActivated = false;
+		public bool IsActivated
+		{
+			get	{	return m_isActivated;	}
+		    internal set
+		    {
+	            if (m_isActivated == value)
+		            return;
+
+	            m_isActivated = value;
+		    }
+		}
+
+		public bool IsDockStateValid(DockState dockState)
+		{
+			if (DockPanel != null && dockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.SystemMdi)
+				return false;
+			else
+				return DockHelper.IsDockStateValid(dockState, DockAreas);
+		}
+
+		private ContextMenu m_tabPageContextMenu = null;
+		public ContextMenu TabPageContextMenu
+		{
+			get	{	return m_tabPageContextMenu;	}
+			set	{	m_tabPageContextMenu = value;	}
+		}
+
+		private string m_toolTipText = null;
+		public string ToolTipText
+		{
+			get	{	return m_toolTipText;	}
+			set {	m_toolTipText = value;	}
+		}
+
+		public void Activate()
+		{
+			if (DockPanel == null)
+				Form.Activate();
+			else if (Pane == null)
+				Show(DockPanel);
+			else
+			{
+				IsHidden = false;
+				Pane.ActiveContent = Content;
+                if (DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.SystemMdi)
+                {
+                    Form.Activate();
+                    return;
+                }
+                else if (DockHelper.IsDockStateAutoHide(DockState))
+                    DockPanel.ActiveAutoHideContent = Content;
+
+                if (!Form.ContainsFocus)
+                    DockPanel.ContentFocusManager.Activate(Content);
+			}
+		}
+
+        public void GiveUpFocus()
+        {
+            DockPanel.ContentFocusManager.GiveUpFocus(Content);
+        }
+
+		private IntPtr m_activeWindowHandle = IntPtr.Zero;
+		internal IntPtr ActiveWindowHandle
+		{
+			get	{	return m_activeWindowHandle;	}
+			set	{	m_activeWindowHandle = value;	}
+		}
+
+		public void Hide()
+		{
+			IsHidden = true;
+		}
+
+        internal void SetPaneAndVisible(DockPane pane)
+        {
+            SetPane(pane);
+            SetVisible();
+        }
+
+		private void SetPane(DockPane pane)
+		{
+			if (pane != null && pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi)
+			{
+				if (Form.Parent is DockPane)
+					SetParent(null);
+				if (Form.MdiParent != DockPanel.ParentForm)
+				{
+					FlagClipWindow = true;
+					Form.MdiParent = DockPanel.ParentForm;
+				}
+			}
+			else
+			{
+				FlagClipWindow = true;
+				if (Form.MdiParent != null)
+					Form.MdiParent = null;
+				if (Form.TopLevel)
+					Form.TopLevel = false;
+				SetParent(pane);
+			}
+		}
+
+		internal void SetVisible()
+		{
+			bool visible;
+
+			if (IsHidden)
+				visible = false;
+			else if (Pane != null && Pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi)
+				visible = true;
+			else if (Pane != null && Pane.ActiveContent == Content)
+				visible = true;
+			else if (Pane != null && Pane.ActiveContent != Content)
+				visible = false;
+			else
+				visible = Form.Visible;
+
+            if (Form.Visible != visible)
+                Form.Visible = visible;
+		}
+
+		private void SetParent(Control value)
+		{
+			if (Form.Parent == value)
+				return;
+
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            // Workaround of .Net Framework bug:
+            // Change the parent of a control with focus may result in the first
+            // MDI child form get activated. 
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            bool bRestoreFocus = false;
+            if (Form.ContainsFocus)
+            {
+				//Suggested as a fix for a memory leak by bugreports
+                if (value == null && !IsFloat)
+                    DockPanel.ContentFocusManager.GiveUpFocus(this.Content);
+                else
+                {
+                    DockPanel.SaveFocus();
+                    bRestoreFocus = true;
+                }
+            }
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+            Form.Parent = value;
+
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            // Workaround of .Net Framework bug:
+            // Change the parent of a control with focus may result in the first
+            // MDI child form get activated. 
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            if (bRestoreFocus)
+                Activate();
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        }
+
+		public void Show()
+		{
+			if (DockPanel == null)
+				Form.Show();
+			else
+				Show(DockPanel);
+		}
+
+		public void Show(DockPanel dockPanel)
+		{
+			if (dockPanel == null)
+				throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel));
+
+			if (DockState == DockState.Unknown)
+				Show(dockPanel, DefaultShowState);
+			else			
+				Activate();
+		}
+
+		public void Show(DockPanel dockPanel, DockState dockState)
+		{
+			if (dockPanel == null)
+				throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel));
+
+			if (dockState == DockState.Unknown || dockState == DockState.Hidden)
+				throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidDockState));
+
+            dockPanel.SuspendLayout(true);
+
+			DockPanel = dockPanel;
+
+			if (dockState == DockState.Float && FloatPane == null)
+				Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Float, true);
+			else if (PanelPane == null)
+			{
+				DockPane paneExisting = null;
+				foreach (DockPane pane in DockPanel.Panes)
+					if (pane.DockState == dockState)
+					{
+						paneExisting = pane;
+						break;
+					}
+
+				if (paneExisting == null)
+					Pane = DockPanel.DockPaneFactory.CreateDockPane(Content, dockState, true);
+				else
+					Pane = paneExisting;
+			}
+
+			DockState = dockState;
+            dockPanel.ResumeLayout(true, true); //we'll resume the layout before activating to ensure that the position
+            Activate();                         //and size of the form are finally processed before the form is shown
+		}
+
+        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")]
+		public void Show(DockPanel dockPanel, Rectangle floatWindowBounds)
+		{
+			if (dockPanel == null)
+				throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullDockPanel));
+
+            dockPanel.SuspendLayout(true);
+
+			DockPanel = dockPanel;
+			if (FloatPane == null)
+			{
+				IsHidden = true;	// to reduce the screen flicker
+				FloatPane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Float, false);
+				FloatPane.FloatWindow.StartPosition = FormStartPosition.Manual;
+			}
+
+			FloatPane.FloatWindow.Bounds = floatWindowBounds;
+			
+			Show(dockPanel, DockState.Float);
+			Activate();
+
+            dockPanel.ResumeLayout(true, true);
+		}
+
+		public void Show(DockPane pane, IDockContent beforeContent)
+		{
+			if (pane == null)
+				throw(new ArgumentNullException(Strings.DockContentHandler_Show_NullPane));
+
+			if (beforeContent != null && pane.Contents.IndexOf(beforeContent) == -1)
+				throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidBeforeContent));
+
+            pane.DockPanel.SuspendLayout(true);
+
+			DockPanel = pane.DockPanel;
+			Pane = pane;
+			pane.SetContentIndex(Content, pane.Contents.IndexOf(beforeContent));
+			Show();
+
+            pane.DockPanel.ResumeLayout(true, true);
+		}
+
+		public void Show(DockPane previousPane, DockAlignment alignment, double proportion)
+		{
+			if (previousPane == null)
+				throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidPrevPane));
+
+			if (DockHelper.IsDockStateAutoHide(previousPane.DockState))
+				throw(new ArgumentException(Strings.DockContentHandler_Show_InvalidPrevPane));
+
+            previousPane.DockPanel.SuspendLayout(true);
+
+			DockPanel = previousPane.DockPanel;
+			DockPanel.DockPaneFactory.CreateDockPane(Content, previousPane, alignment, proportion, true);
+			Show();
+
+            previousPane.DockPanel.ResumeLayout(true, true);
+		}
+
+		public void Close()
+		{
+			DockPanel dockPanel = DockPanel;
+            if (dockPanel != null)
+                dockPanel.SuspendLayout(true);
+			Form.Close();
+			if (dockPanel != null)
+				dockPanel.ResumeLayout(true, true);
+
+		}
+
+		private DockPaneStripBase.Tab m_tab = null;
+		internal DockPaneStripBase.Tab GetTab(DockPaneStripBase dockPaneStrip)
+		{
+            if (m_tab == null)
+                m_tab = dockPaneStrip.CreateTab(Content);
+
+            return m_tab;
+		}
+
+		private IDisposable m_autoHideTab = null;
+		internal IDisposable AutoHideTab
+		{
+            get { return m_autoHideTab; }
+            set { m_autoHideTab = value; }
+		}
+
+		#region Events
+		private static readonly object DockStateChangedEvent = new object();
+		public event EventHandler DockStateChanged
+		{
+			add	{	Events.AddHandler(DockStateChangedEvent, value);	}
+			remove	{	Events.RemoveHandler(DockStateChangedEvent, value);	}
+		}
+		protected virtual void OnDockStateChanged(EventArgs e)
+		{
+			EventHandler handler = (EventHandler)Events[DockStateChangedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+		#endregion
+
+		private void Form_Disposed(object sender, EventArgs e)
+		{
+			Dispose();
+		}
+
+		private void Form_TextChanged(object sender, EventArgs e)
+		{
+			if (DockHelper.IsDockStateAutoHide(DockState))
+				DockPanel.RefreshAutoHideStrip();
+			else if (Pane != null)
+			{
+				if (Pane.FloatWindow != null)
+					Pane.FloatWindow.SetText();
+				Pane.RefreshChanges();
+			}
+		}
+
+		private bool m_flagClipWindow = false;
+		internal bool FlagClipWindow
+		{
+			get	{	return m_flagClipWindow;	}
+			set
+			{
+				if (m_flagClipWindow == value)
+					return;
+
+				m_flagClipWindow = value;
+				if (m_flagClipWindow)
+					Form.Region = new Region(Rectangle.Empty);
+				else
+					Form.Region = null;
+			}
+		}
+
+        private ContextMenuStrip m_tabPageContextMenuStrip = null;
+        public ContextMenuStrip TabPageContextMenuStrip
+        {
+            get { return m_tabPageContextMenuStrip; }
+            set { m_tabPageContextMenuStrip = value; }
+        }
+
+        #region IDockDragSource Members
+
+        Control IDragSource.DragControl
+        {
+            get { return Form; }
+        }
+
+        bool IDockDragSource.CanDockTo(DockPane pane)
+        {
+            if (!IsDockStateValid(pane.DockState))
+                return false;
+
+            if (Pane == pane && pane.DisplayingContents.Count == 1)
+                return false;
+
+            return true;
+        }
+
+        Rectangle IDockDragSource.BeginDrag(Point ptMouse)
+        {
+            Size size;
+            DockPane floatPane = this.FloatPane;
+            if (DockState == DockState.Float || floatPane == null || floatPane.FloatWindow.NestedPanes.Count != 1)
+                size = DockPanel.DefaultFloatWindowSize;
+            else
+                size = floatPane.FloatWindow.Size;
+
+            Point location;
+			Rectangle rectPane = Pane.ClientRectangle;
+            if (DockState == DockState.Document)
+            {
+                if (Pane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    location = new Point(rectPane.Left, rectPane.Bottom - size.Height);
+                else
+                    location = new Point(rectPane.Left, rectPane.Top);
+            }
+            else
+            {
+                location = new Point(rectPane.Left, rectPane.Bottom);
+                location.Y -= size.Height;
+            }
+            location = Pane.PointToScreen(location);
+
+            if (ptMouse.X > location.X + size.Width)
+                location.X += ptMouse.X - (location.X + size.Width) + Measures.SplitterSize;
+
+            return new Rectangle(location, size);
+        }
+
+        public void FloatAt(Rectangle floatWindowBounds)
+        {
+            DockPane pane = DockPanel.DockPaneFactory.CreateDockPane(Content, floatWindowBounds, true);
+        }
+
+        public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex)
+        {
+			if (dockStyle == DockStyle.Fill)
+			{
+				bool samePane = (Pane == pane);
+				if (!samePane)
+					Pane = pane;
+
+				if (contentIndex == -1 || !samePane)
+					pane.SetContentIndex(Content, contentIndex);
+				else
+				{
+					DockContentCollection contents = pane.Contents;
+					int oldIndex = contents.IndexOf(Content);
+					int newIndex = contentIndex;
+					if (oldIndex < newIndex)
+					{
+						newIndex += 1;
+						if (newIndex > contents.Count -1)
+							newIndex = -1;
+					}
+					pane.SetContentIndex(Content, newIndex);
+				}
+			}
+			else
+			{
+				DockPane paneFrom = DockPanel.DockPaneFactory.CreateDockPane(Content, pane.DockState, true);
+				INestedPanesContainer container = pane.NestedPanesContainer;
+				if (dockStyle == DockStyle.Left)
+					paneFrom.DockTo(container, pane, DockAlignment.Left, 0.5);
+				else if (dockStyle == DockStyle.Right) 
+					paneFrom.DockTo(container, pane, DockAlignment.Right, 0.5);
+				else if (dockStyle == DockStyle.Top)
+					paneFrom.DockTo(container, pane, DockAlignment.Top, 0.5);
+				else if (dockStyle == DockStyle.Bottom) 
+					paneFrom.DockTo(container, pane, DockAlignment.Bottom, 0.5);
+
+				paneFrom.DockState = pane.DockState;
+			}
+        }
+
+        public void DockTo(DockPanel panel, DockStyle dockStyle)
+        {
+            if (panel != DockPanel)
+                throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel");
+
+            DockPane pane;
+
+            if (dockStyle == DockStyle.Top)
+                pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockTop, true);
+            else if (dockStyle == DockStyle.Bottom)
+                pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockBottom, true);
+            else if (dockStyle == DockStyle.Left)
+                pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockLeft, true);
+            else if (dockStyle == DockStyle.Right)
+                pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.DockRight, true);
+            else if (dockStyle == DockStyle.Fill)
+                pane = DockPanel.DockPaneFactory.CreateDockPane(Content, DockState.Document, true);
+            else
+                return;
+        }
+
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockOutlineBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockOutlineBase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockOutlineBase.cs	(revision 2645)
@@ -0,0 +1,161 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    internal abstract class DockOutlineBase
+    {
+        public DockOutlineBase()
+        {
+            Init();
+        }
+
+        private void Init()
+        {
+            SetValues(Rectangle.Empty, null, DockStyle.None, -1);
+            SaveOldValues();
+        }
+
+        private Rectangle m_oldFloatWindowBounds;
+        protected Rectangle OldFloatWindowBounds
+        {
+            get { return m_oldFloatWindowBounds; }
+        }
+
+        private Control m_oldDockTo;
+        protected Control OldDockTo
+        {
+            get { return m_oldDockTo; }
+        }
+
+        private DockStyle m_oldDock;
+        protected DockStyle OldDock
+        {
+            get { return m_oldDock; }
+        }
+
+        private int m_oldContentIndex;
+        protected int OldContentIndex
+        {
+            get { return m_oldContentIndex; }
+        }
+
+        protected bool SameAsOldValue
+        {
+            get
+            {
+                return FloatWindowBounds == OldFloatWindowBounds &&
+                    DockTo == OldDockTo &&
+                    Dock == OldDock &&
+                    ContentIndex == OldContentIndex;
+            }
+        }
+
+        private Rectangle m_floatWindowBounds;
+        public Rectangle FloatWindowBounds
+        {
+            get { return m_floatWindowBounds; }
+        }
+
+        private Control m_dockTo;
+        public Control DockTo
+        {
+            get { return m_dockTo; }
+        }
+
+        private DockStyle m_dock;
+        public DockStyle Dock
+        {
+            get { return m_dock; }
+        }
+
+        private int m_contentIndex;
+        public int ContentIndex
+        {
+            get { return m_contentIndex; }
+        }
+
+        public bool FlagFullEdge
+        {
+            get { return m_contentIndex != 0; }
+        }
+
+        private bool m_flagTestDrop = false;
+        public bool FlagTestDrop
+        {
+            get { return m_flagTestDrop; }
+            set { m_flagTestDrop = value; }
+        }
+
+        private void SaveOldValues()
+        {
+            m_oldDockTo = m_dockTo;
+            m_oldDock = m_dock;
+            m_oldContentIndex = m_contentIndex;
+            m_oldFloatWindowBounds = m_floatWindowBounds;
+        }
+
+        protected abstract void OnShow();
+
+        protected abstract void OnClose();
+
+        private void SetValues(Rectangle floatWindowBounds, Control dockTo, DockStyle dock, int contentIndex)
+        {
+            m_floatWindowBounds = floatWindowBounds;
+            m_dockTo = dockTo;
+            m_dock = dock;
+            m_contentIndex = contentIndex;
+            FlagTestDrop = true;
+        }
+
+        private void TestChange()
+        {
+            if (m_floatWindowBounds != m_oldFloatWindowBounds ||
+                m_dockTo != m_oldDockTo ||
+                m_dock != m_oldDock ||
+                m_contentIndex != m_oldContentIndex)
+                OnShow();
+        }
+
+        public void Show()
+        {
+            SaveOldValues();
+            SetValues(Rectangle.Empty, null, DockStyle.None, -1);
+            TestChange();
+        }
+
+        public void Show(DockPane pane, DockStyle dock)
+        {
+            SaveOldValues();
+            SetValues(Rectangle.Empty, pane, dock, -1);
+            TestChange();
+        }
+
+        public void Show(DockPane pane, int contentIndex)
+        {
+            SaveOldValues();
+            SetValues(Rectangle.Empty, pane, DockStyle.Fill, contentIndex);
+            TestChange();
+        }
+
+        public void Show(DockPanel dockPanel, DockStyle dock, bool fullPanelEdge)
+        {
+            SaveOldValues();
+            SetValues(Rectangle.Empty, dockPanel, dock, fullPanelEdge ? -1 : 0);
+            TestChange();
+        }
+
+        public void Show(Rectangle floatWindowBounds)
+        {
+            SaveOldValues();
+            SetValues(floatWindowBounds, null, DockStyle.None, -1);
+            TestChange();
+        }
+
+        public void Close()
+        {
+            OnClose();
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPane.SplitterControl.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPane.SplitterControl.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPane.SplitterControl.cs	(revision 2645)
@@ -0,0 +1,157 @@
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPane
+    {
+        private class SplitterControl : Control, ISplitterDragSource
+        {
+            DockPane m_pane;
+
+            public SplitterControl(DockPane pane)
+            {
+                SetStyle(ControlStyles.Selectable, false);
+                m_pane = pane;
+            }
+
+            public DockPane DockPane
+            {
+                get { return m_pane; }
+            }
+
+            private DockAlignment m_alignment;
+            public DockAlignment Alignment
+            {
+                get { return m_alignment; }
+                set
+                {
+                    m_alignment = value;
+                    if (m_alignment == DockAlignment.Left || m_alignment == DockAlignment.Right)
+                        Cursor = Cursors.VSplit;
+                    else if (m_alignment == DockAlignment.Top || m_alignment == DockAlignment.Bottom)
+                        Cursor = Cursors.HSplit;
+                    else
+                        Cursor = Cursors.Default;
+
+                    if (DockPane.DockState == DockState.Document)
+                        Invalidate();
+                }
+            }
+
+            protected override void OnPaint(PaintEventArgs e)
+            {
+                base.OnPaint(e);
+
+                if (DockPane.DockState != DockState.Document)
+                    return;
+
+                Graphics g = e.Graphics;
+                Rectangle rect = ClientRectangle;
+                if (Alignment == DockAlignment.Top || Alignment == DockAlignment.Bottom)
+                    g.DrawLine(SystemPens.ControlDark, rect.Left, rect.Bottom - 1, rect.Right, rect.Bottom - 1);
+                else if (Alignment == DockAlignment.Left || Alignment == DockAlignment.Right)
+                    g.DrawLine(SystemPens.ControlDarkDark, rect.Right - 1, rect.Top, rect.Right - 1, rect.Bottom);
+            }
+
+            protected override void OnMouseDown(MouseEventArgs e)
+            {
+                base.OnMouseDown(e);
+
+                if (e.Button != MouseButtons.Left)
+                    return;
+
+                DockPane.DockPanel.BeginDrag(this, Parent.RectangleToScreen(Bounds));
+            }
+
+            #region ISplitterDragSource Members
+
+            void ISplitterDragSource.BeginDrag(Rectangle rectSplitter)
+            {
+            }
+
+            void ISplitterDragSource.EndDrag()
+            {
+            }
+
+            bool ISplitterDragSource.IsVertical
+            {
+                get
+                {
+                    NestedDockingStatus status = DockPane.NestedDockingStatus;
+                    return (status.DisplayingAlignment == DockAlignment.Left ||
+                        status.DisplayingAlignment == DockAlignment.Right);
+                }
+            }
+
+            Rectangle ISplitterDragSource.DragLimitBounds
+            {
+                get
+                {
+                    NestedDockingStatus status = DockPane.NestedDockingStatus;
+                    Rectangle rectLimit = Parent.RectangleToScreen(status.LogicalBounds);
+                    if (((ISplitterDragSource)this).IsVertical)
+                    {
+                        rectLimit.X += MeasurePane.MinSize;
+                        rectLimit.Width -= 2 * MeasurePane.MinSize;
+                    }
+                    else
+                    {
+                        rectLimit.Y += MeasurePane.MinSize;
+                        rectLimit.Height -= 2 * MeasurePane.MinSize;
+                    }
+
+                    return rectLimit;
+                }
+            }
+
+            void ISplitterDragSource.MoveSplitter(int offset)
+            {
+                NestedDockingStatus status = DockPane.NestedDockingStatus;
+                double proportion = status.Proportion;
+                if (status.LogicalBounds.Width <= 0 || status.LogicalBounds.Height <= 0)
+                    return;
+                else if (status.DisplayingAlignment == DockAlignment.Left)
+                    proportion += ((double)offset) / (double)status.LogicalBounds.Width;
+                else if (status.DisplayingAlignment == DockAlignment.Right)
+                    proportion -= ((double)offset) / (double)status.LogicalBounds.Width;
+                else if (status.DisplayingAlignment == DockAlignment.Top)
+                    proportion += ((double)offset) / (double)status.LogicalBounds.Height;
+                else
+                    proportion -= ((double)offset) / (double)status.LogicalBounds.Height;
+
+                DockPane.SetNestedDockingProportion(proportion);
+            }
+
+            #region IDragSource Members
+
+            Control IDragSource.DragControl
+            {
+                get { return this; }
+            }
+
+            #endregion
+
+            #endregion
+        }
+
+        private SplitterControl m_splitter;
+        private SplitterControl Splitter
+        {
+            get { return m_splitter; }
+        }
+
+        internal Rectangle SplitterBounds
+        {
+            set { Splitter.Bounds = value; }
+        }
+
+        internal DockAlignment SplitterAlignment
+        {
+            set { Splitter.Alignment = value; }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPane.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPane.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPane.cs	(revision 2645)
@@ -0,0 +1,1288 @@
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	[ToolboxItem(false)]
+	public partial class DockPane : UserControl, IDockDragSource
+	{
+		public enum AppearanceStyle
+		{
+			ToolWindow,
+			Document
+		}
+
+		private enum HitTestArea
+		{
+			Caption,
+			TabStrip,
+			Content,
+			None
+		}
+
+		private struct HitTestResult
+		{
+			public HitTestArea HitArea;
+			public int Index;
+
+			public HitTestResult(HitTestArea hitTestArea, int index)
+			{
+				HitArea = hitTestArea;
+				Index = index;
+			}
+		}
+
+		private DockPaneCaptionBase m_captionControl;
+		private DockPaneCaptionBase CaptionControl
+		{
+			get	{	return m_captionControl;	}
+		}
+
+		private DockPaneStripBase m_tabStripControl;
+		internal DockPaneStripBase TabStripControl
+		{
+			get	{	return m_tabStripControl;	}
+		}
+
+		internal protected DockPane(IDockContent content, DockState visibleState, bool show)
+		{
+			InternalConstruct(content, visibleState, false, Rectangle.Empty, null, DockAlignment.Right, 0.5, show);
+		}
+
+        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")]
+		internal protected DockPane(IDockContent content, FloatWindow floatWindow, bool show)
+		{
+            if (floatWindow == null)
+                throw new ArgumentNullException("floatWindow");
+
+			InternalConstruct(content, DockState.Float, false, Rectangle.Empty, floatWindow.NestedPanes.GetDefaultPreviousPane(this), DockAlignment.Right, 0.5, show);
+		}
+
+		internal protected DockPane(IDockContent content, DockPane previousPane, DockAlignment alignment, double proportion, bool show)
+		{
+			if (previousPane == null)
+				throw(new ArgumentNullException("previousPane"));
+			InternalConstruct(content, previousPane.DockState, false, Rectangle.Empty, previousPane, alignment, proportion, show);
+		}
+
+        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")]
+        internal protected DockPane(IDockContent content, Rectangle floatWindowBounds, bool show)
+		{
+			InternalConstruct(content, DockState.Float, true, floatWindowBounds, null, DockAlignment.Right, 0.5, show);
+		}
+
+		private void InternalConstruct(IDockContent content, DockState dockState, bool flagBounds, Rectangle floatWindowBounds, DockPane prevPane, DockAlignment alignment, double proportion, bool show)
+		{
+			if (dockState == DockState.Hidden || dockState == DockState.Unknown)
+				throw new ArgumentException(Strings.DockPane_SetDockState_InvalidState);
+
+			if (content == null)
+				throw new ArgumentNullException(Strings.DockPane_Constructor_NullContent);
+
+			if (content.DockHandler.DockPanel == null)
+				throw new ArgumentException(Strings.DockPane_Constructor_NullDockPanel);
+
+
+			SuspendLayout();
+			SetStyle(ControlStyles.Selectable, false);
+
+			m_isFloat = (dockState == DockState.Float);
+
+			m_contents = new DockContentCollection();
+			m_displayingContents = new DockContentCollection(this);
+			m_dockPanel = content.DockHandler.DockPanel;
+			m_dockPanel.AddPane(this);
+
+			m_splitter = new SplitterControl(this);
+
+			m_nestedDockingStatus = new NestedDockingStatus(this);
+
+			m_captionControl = DockPanel.DockPaneCaptionFactory.CreateDockPaneCaption(this);
+			m_tabStripControl = DockPanel.DockPaneStripFactory.CreateDockPaneStrip(this);
+			Controls.AddRange(new Control[] {	m_captionControl, m_tabStripControl	});
+			
+			DockPanel.SuspendLayout(true);
+			if (flagBounds)
+				FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this, floatWindowBounds);
+			else if (prevPane != null)
+				DockTo(prevPane.NestedPanesContainer, prevPane, alignment, proportion);
+
+			SetDockState(dockState);
+			if (show)
+				content.DockHandler.Pane = this;
+			else if (this.IsFloat)
+				content.DockHandler.FloatPane = this;
+			else
+				content.DockHandler.PanelPane = this;
+
+			ResumeLayout();
+			DockPanel.ResumeLayout(true, true);
+		}
+
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing)
+			{
+				m_dockState = DockState.Unknown;
+
+				if (NestedPanesContainer != null)
+					NestedPanesContainer.NestedPanes.Remove(this);
+
+				if (DockPanel != null)
+				{
+					DockPanel.RemovePane(this);
+					m_dockPanel = null;
+				}
+
+				Splitter.Dispose();
+                if (m_autoHidePane != null)
+				    m_autoHidePane.Dispose();
+			}
+			base.Dispose(disposing);
+		}
+
+		private IDockContent m_activeContent = null;
+		public virtual IDockContent ActiveContent
+		{
+			get	{	return m_activeContent;	}
+			set
+			{
+				if (ActiveContent == value)
+					return;
+
+				if (value != null)
+				{
+					if (!DisplayingContents.Contains(value))
+						throw(new InvalidOperationException(Strings.DockPane_ActiveContent_InvalidValue));
+				}
+				else
+				{
+					if (DisplayingContents.Count != 0)
+						throw(new InvalidOperationException(Strings.DockPane_ActiveContent_InvalidValue));
+				}
+
+				IDockContent oldValue = m_activeContent;
+
+				if (DockPanel.ActiveAutoHideContent == oldValue)
+					DockPanel.ActiveAutoHideContent = null;
+
+				m_activeContent = value;
+
+				if (DockPanel.DocumentStyle == DocumentStyle.DockingMdi && DockState == DockState.Document)
+				{
+					if (m_activeContent != null)
+						m_activeContent.DockHandler.Form.BringToFront();
+				}
+				else
+				{
+					if (m_activeContent != null)
+						m_activeContent.DockHandler.SetVisible();
+					if (oldValue != null && DisplayingContents.Contains(oldValue))
+						oldValue.DockHandler.SetVisible();
+                    if (IsActivated && m_activeContent != null)
+                        m_activeContent.DockHandler.Activate();
+				}
+
+				if (FloatWindow != null)
+					FloatWindow.SetText();
+
+                if (DockPanel.DocumentStyle == DocumentStyle.DockingMdi &&
+                    DockState == DockState.Document)
+                    RefreshChanges(false);  // delayed layout to reduce screen flicker
+                else
+                    RefreshChanges();
+
+				if (m_activeContent != null)
+					TabStripControl.EnsureTabVisible(m_activeContent);
+			}
+		}
+		
+		private bool m_allowDockDragAndDrop = true;
+		public virtual bool AllowDockDragAndDrop
+		{
+			get	{	return m_allowDockDragAndDrop;	}
+			set	{	m_allowDockDragAndDrop = value;	}
+		}
+
+        private IDisposable m_autoHidePane = null;
+        internal IDisposable AutoHidePane
+        {
+            get { return m_autoHidePane; }
+            set { m_autoHidePane = value; }
+        }
+
+        private object m_autoHideTabs = null;
+        internal object AutoHideTabs
+        {
+            get { return m_autoHideTabs; }
+            set { m_autoHideTabs = value; }
+        }
+
+        private object TabPageContextMenu
+        {
+            get
+            {
+                IDockContent content = ActiveContent;
+
+                if (content == null)
+                    return null;
+
+                if (content.DockHandler.TabPageContextMenuStrip != null)
+                    return content.DockHandler.TabPageContextMenuStrip;
+                else if (content.DockHandler.TabPageContextMenu != null)
+                    return content.DockHandler.TabPageContextMenu;
+                else
+                    return null;
+            }
+        }
+
+        internal bool HasTabPageContextMenu
+        {
+            get { return TabPageContextMenu != null; }
+        }
+
+        internal void ShowTabPageContextMenu(Control control, Point position)
+        {
+            object menu = TabPageContextMenu;
+
+            if (menu == null)
+                return;
+
+            ContextMenuStrip contextMenuStrip = menu as ContextMenuStrip;
+            if (contextMenuStrip != null)
+            {
+                contextMenuStrip.Show(control, position);
+                return;
+            }
+
+            ContextMenu contextMenu = menu as ContextMenu;
+            if (contextMenu != null)
+                contextMenu.Show(this, position);
+        }
+
+		private Rectangle CaptionRectangle
+		{
+			get
+			{
+				if (!HasCaption)
+					return Rectangle.Empty;
+
+				Rectangle rectWindow = DisplayingRectangle;
+				int x, y, width;
+				x = rectWindow.X;
+				y = rectWindow.Y;
+				width = rectWindow.Width;
+				int height = CaptionControl.MeasureHeight();
+
+				return new Rectangle(x, y, width, height);
+			}
+		}
+
+		internal Rectangle ContentRectangle
+		{
+			get
+			{
+				Rectangle rectWindow = DisplayingRectangle;
+				Rectangle rectCaption = CaptionRectangle;
+				Rectangle rectTabStrip = TabStripRectangle;
+
+				int x = rectWindow.X;
+
+                int y = rectWindow.Y + (rectCaption.IsEmpty ? 0 : rectCaption.Height);
+                if (DockState == DockState.Document && DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Top)
+                    y += rectTabStrip.Height;
+                
+				int width = rectWindow.Width;
+				int height = rectWindow.Height - rectCaption.Height - rectTabStrip.Height;
+
+				return new Rectangle(x, y, width, height);
+			}
+		}
+
+		internal Rectangle TabStripRectangle
+		{
+			get
+			{
+				if (Appearance == AppearanceStyle.ToolWindow)
+					return TabStripRectangle_ToolWindow;
+				else
+					return TabStripRectangle_Document;
+			}
+		}
+
+		private Rectangle TabStripRectangle_ToolWindow
+		{
+			get
+			{
+				if (DisplayingContents.Count <= 1 || IsAutoHide)
+					return Rectangle.Empty;
+
+				Rectangle rectWindow = DisplayingRectangle;
+
+				int width = rectWindow.Width;
+				int height = TabStripControl.MeasureHeight();
+				int x = rectWindow.X;
+				int y = rectWindow.Bottom - height;
+				Rectangle rectCaption = CaptionRectangle;
+				if (rectCaption.Contains(x, y))
+					y = rectCaption.Y + rectCaption.Height;
+
+				return new Rectangle(x, y, width, height);
+			}
+		}
+
+		private Rectangle TabStripRectangle_Document
+		{
+			get
+			{
+				if (DisplayingContents.Count == 0)
+					return Rectangle.Empty;
+
+				if (DisplayingContents.Count == 1 && DockPanel.DocumentStyle == DocumentStyle.DockingSdi)
+					return Rectangle.Empty;
+
+				Rectangle rectWindow = DisplayingRectangle;
+				int x = rectWindow.X;
+				int width = rectWindow.Width;
+				int height = TabStripControl.MeasureHeight();
+
+                int y = 0;
+                if (DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    y = rectWindow.Height - height;
+                else
+                    y = rectWindow.Y;
+
+				return new Rectangle(x, y, width, height);
+			}
+		}
+
+		public virtual string CaptionText
+		{
+			get	{	return ActiveContent == null ? string.Empty : ActiveContent.DockHandler.TabText;	}
+		}
+
+		private DockContentCollection m_contents;
+		public DockContentCollection Contents
+		{
+			get	{	return m_contents;	}
+		}
+
+		private DockContentCollection m_displayingContents;
+		public DockContentCollection DisplayingContents
+		{
+			get	{	return m_displayingContents;	}
+		}
+
+		private DockPanel m_dockPanel;
+		public DockPanel DockPanel
+		{
+			get	{	return m_dockPanel;	}
+		}
+
+		private bool HasCaption
+		{
+			get
+			{	
+				if (DockState == DockState.Document ||
+					DockState == DockState.Hidden ||
+					DockState == DockState.Unknown ||
+					(DockState == DockState.Float && FloatWindow.VisibleNestedPanes.Count <= 1))
+					return false;
+				else
+					return true;
+			}
+		}
+
+		private bool m_isActivated = false;
+		public bool IsActivated
+		{
+			get	{	return m_isActivated;	}
+		}
+		internal void SetIsActivated(bool value)
+		{
+			if (m_isActivated == value)
+				return;
+
+			m_isActivated = value;
+			if (DockState != DockState.Document)
+				RefreshChanges(false);
+			OnIsActivatedChanged(EventArgs.Empty);
+		}
+
+		private bool m_isActiveDocumentPane = false;
+		public bool IsActiveDocumentPane
+		{
+			get	{	return m_isActiveDocumentPane;	}
+		}
+		internal void SetIsActiveDocumentPane(bool value)
+		{
+			if (m_isActiveDocumentPane == value)
+				return;
+
+			m_isActiveDocumentPane = value;
+			if (DockState == DockState.Document)
+				RefreshChanges();
+			OnIsActiveDocumentPaneChanged(EventArgs.Empty);
+		}
+
+		public bool IsDockStateValid(DockState dockState)
+		{
+			foreach (IDockContent content in Contents)
+				if (!content.DockHandler.IsDockStateValid(dockState))
+					return false;
+
+			return true;
+		}
+
+		public bool IsAutoHide
+		{
+			get	{	return DockHelper.IsDockStateAutoHide(DockState);	}
+		}
+
+		public AppearanceStyle Appearance
+		{
+			get	{	return (DockState == DockState.Document) ? AppearanceStyle.Document : AppearanceStyle.ToolWindow;	}
+		}
+
+		internal Rectangle DisplayingRectangle
+		{
+			get	{	return ClientRectangle;	}
+		}
+
+		public void Activate()
+		{
+			if (DockHelper.IsDockStateAutoHide(DockState) && DockPanel.ActiveAutoHideContent != ActiveContent)
+				DockPanel.ActiveAutoHideContent = ActiveContent;
+			else if (!IsActivated && ActiveContent != null)
+				ActiveContent.DockHandler.Activate();
+		}
+
+		internal void AddContent(IDockContent content)
+		{
+			if (Contents.Contains(content))
+				return;
+
+			Contents.Add(content);
+		}
+
+		internal void Close()
+		{
+			Dispose();
+		}
+
+		public void CloseActiveContent()
+		{
+			CloseContent(ActiveContent);
+		}
+
+		internal void CloseContent(IDockContent content)
+		{
+            DockPanel dockPanel = DockPanel;
+            dockPanel.SuspendLayout(true);
+
+			if (content == null)
+				return;
+
+			if (!content.DockHandler.CloseButton)
+				return;
+
+			if (content.DockHandler.HideOnClose)
+				content.DockHandler.Hide();
+			else
+				content.DockHandler.Close();
+
+            dockPanel.ResumeLayout(true, true);
+        }
+
+		private HitTestResult GetHitTest(Point ptMouse)
+		{
+			Point ptMouseClient = PointToClient(ptMouse);
+
+			Rectangle rectCaption = CaptionRectangle;
+			if (rectCaption.Contains(ptMouseClient))
+				return new HitTestResult(HitTestArea.Caption, -1);
+
+			Rectangle rectContent = ContentRectangle;
+			if (rectContent.Contains(ptMouseClient))
+				return new HitTestResult(HitTestArea.Content, -1);
+
+			Rectangle rectTabStrip = TabStripRectangle;
+			if (rectTabStrip.Contains(ptMouseClient))
+				return new HitTestResult(HitTestArea.TabStrip, TabStripControl.HitTest(TabStripControl.PointToClient(ptMouse)));
+
+			return new HitTestResult(HitTestArea.None, -1);
+		}
+
+		private bool m_isHidden = true;
+		public bool IsHidden
+		{
+			get	{	return m_isHidden;	}
+		}
+		private void SetIsHidden(bool value)
+		{
+			if (m_isHidden == value)
+				return;
+
+			m_isHidden = value;
+			if (DockHelper.IsDockStateAutoHide(DockState))
+			{
+				DockPanel.RefreshAutoHideStrip();
+				DockPanel.PerformLayout();
+			}
+			else if (NestedPanesContainer != null)
+				((Control)NestedPanesContainer).PerformLayout();
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+			SetIsHidden(DisplayingContents.Count == 0);
+			if (!IsHidden)
+			{
+				CaptionControl.Bounds = CaptionRectangle;
+				TabStripControl.Bounds = TabStripRectangle;
+
+				SetContentBounds();
+
+				foreach (IDockContent content in Contents)
+				{
+					if (DisplayingContents.Contains(content))
+						if (content.DockHandler.FlagClipWindow && content.DockHandler.Form.Visible)
+							content.DockHandler.FlagClipWindow = false;
+				}
+			}
+
+			base.OnLayout(levent);
+		}
+
+		internal void SetContentBounds()
+		{
+			Rectangle rectContent = ContentRectangle;
+            if (DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi)
+                rectContent = DockPanel.RectangleToMdiClient(RectangleToScreen(rectContent));
+
+            Rectangle rectInactive = new Rectangle(-rectContent.Width, rectContent.Y, rectContent.Width, rectContent.Height);
+			foreach (IDockContent content in Contents)
+                if (content.DockHandler.Pane == this)
+                {
+                    if (content == ActiveContent)
+                        content.DockHandler.Form.Bounds = rectContent;
+                    else
+                        content.DockHandler.Form.Bounds = rectInactive;
+                }
+		}
+
+		internal void RefreshChanges()
+		{
+            RefreshChanges(true);
+		}
+
+        private void RefreshChanges(bool performLayout)
+        {
+            if (IsDisposed)
+                return;
+
+            CaptionControl.RefreshChanges();
+            TabStripControl.RefreshChanges();
+            if (DockState == DockState.Float)
+                FloatWindow.RefreshChanges();
+            if (DockHelper.IsDockStateAutoHide(DockState) && DockPanel != null)
+            {
+                DockPanel.RefreshAutoHideStrip();
+                DockPanel.PerformLayout();
+            }
+
+            if (performLayout)
+                PerformLayout();
+        }
+
+		internal void RemoveContent(IDockContent content)
+		{
+			if (!Contents.Contains(content))
+				return;
+			
+			Contents.Remove(content);
+		}
+
+		public void SetContentIndex(IDockContent content, int index)
+		{
+			int oldIndex = Contents.IndexOf(content);
+			if (oldIndex == -1)
+				throw(new ArgumentException(Strings.DockPane_SetContentIndex_InvalidContent));
+
+			if (index < 0 || index > Contents.Count - 1)
+				if (index != -1)
+					throw(new ArgumentOutOfRangeException(Strings.DockPane_SetContentIndex_InvalidIndex));
+				
+			if (oldIndex == index)
+				return;
+			if (oldIndex == Contents.Count - 1 && index == -1)
+				return;
+
+			Contents.Remove(content);
+			if (index == -1)
+				Contents.Add(content);
+			else if (oldIndex < index)
+				Contents.AddAt(content, index - 1);
+			else
+				Contents.AddAt(content, index);
+
+			RefreshChanges();
+		}
+
+		private void SetParent()
+		{
+			if (DockState == DockState.Unknown || DockState == DockState.Hidden)
+			{
+				SetParent(null);
+				Splitter.Parent = null;
+			}
+			else if (DockState == DockState.Float)
+			{
+				SetParent(FloatWindow);
+				Splitter.Parent = FloatWindow;
+			}
+			else if (DockHelper.IsDockStateAutoHide(DockState))
+			{
+				SetParent(DockPanel.AutoHideControl);
+				Splitter.Parent = null;
+			}
+			else
+			{
+				SetParent(DockPanel.DockWindows[DockState]);
+				Splitter.Parent = Parent;
+			}
+		}
+
+		private void SetParent(Control value)
+		{
+			if (Parent == value)
+				return;
+
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            // Workaround of .Net Framework bug:
+            // Change the parent of a control with focus may result in the first
+            // MDI child form get activated. 
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            IDockContent contentFocused = GetFocusedContent();
+            if (contentFocused != null)
+                DockPanel.SaveFocus();
+
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+            Parent = value;
+
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            // Workaround of .Net Framework bug:
+            // Change the parent of a control with focus may result in the first
+            // MDI child form get activated. 
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+            if (contentFocused != null)
+                contentFocused.DockHandler.Activate();
+            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        }
+
+		public new void Show()
+		{
+			Activate();
+		}
+
+        internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline)
+        {
+            if (!dragSource.CanDockTo(this))
+                return;
+
+            Point ptMouse = Control.MousePosition;
+
+            HitTestResult hitTestResult = GetHitTest(ptMouse);
+            if (hitTestResult.HitArea == HitTestArea.Caption)
+                dockOutline.Show(this, -1);
+            else if (hitTestResult.HitArea == HitTestArea.TabStrip && hitTestResult.Index != -1)
+                dockOutline.Show(this, hitTestResult.Index);
+        }
+
+		internal void ValidateActiveContent()
+		{
+			if (ActiveContent == null)
+			{
+				if (DisplayingContents.Count != 0)
+					ActiveContent = DisplayingContents[0];
+				return;
+			}
+
+			if (DisplayingContents.IndexOf(ActiveContent) >= 0)
+				return;
+
+			IDockContent prevVisible = null;
+			for (int i=Contents.IndexOf(ActiveContent)-1; i>=0; i--)
+				if (Contents[i].DockHandler.DockState == DockState)
+				{
+					prevVisible = Contents[i];
+					break;
+				}
+
+			IDockContent nextVisible = null;
+			for (int i=Contents.IndexOf(ActiveContent)+1; i<Contents.Count; i++)
+				if (Contents[i].DockHandler.DockState == DockState)
+				{
+					nextVisible = Contents[i];
+					break;
+				}
+
+			if (prevVisible != null)
+				ActiveContent = prevVisible;
+			else if (nextVisible != null)
+				ActiveContent = nextVisible;
+			else
+				ActiveContent = null;
+		}
+
+		private static readonly object DockStateChangedEvent = new object();
+		public event EventHandler DockStateChanged
+		{
+			add	{	Events.AddHandler(DockStateChangedEvent, value);	}
+			remove	{	Events.RemoveHandler(DockStateChangedEvent, value);	}
+		}
+		protected virtual void OnDockStateChanged(EventArgs e)
+		{
+			EventHandler handler = (EventHandler)Events[DockStateChangedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+
+		private static readonly object IsActivatedChangedEvent = new object();
+		public event EventHandler IsActivatedChanged
+		{
+			add	{	Events.AddHandler(IsActivatedChangedEvent, value);	}
+			remove	{	Events.RemoveHandler(IsActivatedChangedEvent, value);	}
+		}
+		protected virtual void OnIsActivatedChanged(EventArgs e)
+		{
+			EventHandler handler = (EventHandler)Events[IsActivatedChangedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+
+		private static readonly object IsActiveDocumentPaneChangedEvent = new object();
+		public event EventHandler IsActiveDocumentPaneChanged
+		{
+			add	{	Events.AddHandler(IsActiveDocumentPaneChangedEvent, value);	}
+			remove	{	Events.RemoveHandler(IsActiveDocumentPaneChangedEvent, value);	}
+		}
+		protected virtual void OnIsActiveDocumentPaneChanged(EventArgs e)
+		{
+			EventHandler handler = (EventHandler)Events[IsActiveDocumentPaneChangedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+
+		public DockWindow DockWindow
+		{
+			get	{	return (m_nestedDockingStatus.NestedPanes == null) ? null : m_nestedDockingStatus.NestedPanes.Container as DockWindow;	}
+			set
+			{
+				DockWindow oldValue = DockWindow;
+				if (oldValue == value)
+					return;
+
+				DockTo(value);
+			}
+		}
+
+		public FloatWindow FloatWindow
+		{
+			get	{	return (m_nestedDockingStatus.NestedPanes == null) ? null : m_nestedDockingStatus.NestedPanes.Container as FloatWindow;	}
+			set
+			{
+				FloatWindow oldValue = FloatWindow;
+				if (oldValue == value)
+					return;
+
+				DockTo(value);
+			}
+		}
+
+		private NestedDockingStatus m_nestedDockingStatus;
+		public NestedDockingStatus NestedDockingStatus
+		{
+			get	{	return m_nestedDockingStatus;	}
+		}
+	
+		private bool m_isFloat;
+		public bool IsFloat
+		{
+			get	{	return m_isFloat;	}
+		}
+
+		public INestedPanesContainer NestedPanesContainer
+		{
+			get
+			{
+				if (NestedDockingStatus.NestedPanes == null)
+					return null;
+				else
+					return NestedDockingStatus.NestedPanes.Container;
+			}
+		}
+
+		private DockState m_dockState = DockState.Unknown;
+		public DockState DockState
+		{
+			get	{	return m_dockState;	}
+			set
+			{
+				SetDockState(value);
+			}
+		}
+
+		public DockPane SetDockState(DockState value)
+		{
+			if (value == DockState.Unknown || value == DockState.Hidden)
+				throw new InvalidOperationException(Strings.DockPane_SetDockState_InvalidState);
+
+			if ((value == DockState.Float) == this.IsFloat)
+			{
+				InternalSetDockState(value);
+				return this;
+			}
+
+			if (DisplayingContents.Count == 0)
+				return null;
+
+			IDockContent firstContent = null;
+			for (int i=0; i<DisplayingContents.Count; i++)
+			{
+				IDockContent content = DisplayingContents[i];
+				if (content.DockHandler.IsDockStateValid(value))
+				{
+					firstContent = content;
+					break;
+				}
+			}
+			if (firstContent == null)
+				return null;
+
+			firstContent.DockHandler.DockState = value;
+			DockPane pane = firstContent.DockHandler.Pane;
+			DockPanel.SuspendLayout(true);
+			for (int i=0; i<DisplayingContents.Count; i++)
+			{
+				IDockContent content = DisplayingContents[i];
+				if (content.DockHandler.IsDockStateValid(value))
+					content.DockHandler.Pane = pane;
+			}
+			DockPanel.ResumeLayout(true, true);
+			return pane;
+		}
+
+		private void InternalSetDockState(DockState value)
+		{
+			if (m_dockState == value)
+				return;
+
+			DockState oldDockState = m_dockState;
+			INestedPanesContainer oldContainer = NestedPanesContainer;
+
+			m_dockState = value;
+
+			SuspendRefreshStateChange();
+
+            IDockContent contentFocused = GetFocusedContent();
+            if (contentFocused != null)
+                DockPanel.SaveFocus();
+
+            if (!IsFloat)
+                DockWindow = DockPanel.DockWindows[DockState];
+            else if (FloatWindow == null)
+                FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this);
+
+            if (contentFocused != null)
+                DockPanel.ContentFocusManager.Activate(contentFocused);
+
+			ResumeRefreshStateChange(oldContainer, oldDockState);
+        }
+
+		private int m_countRefreshStateChange = 0;
+		private void SuspendRefreshStateChange()
+		{
+			m_countRefreshStateChange ++;
+			DockPanel.SuspendLayout(true);
+		}
+
+		private void ResumeRefreshStateChange()
+		{
+			m_countRefreshStateChange --;
+			System.Diagnostics.Debug.Assert(m_countRefreshStateChange >= 0);
+			DockPanel.ResumeLayout(true, true);
+		}
+
+		private bool IsRefreshStateChangeSuspended
+		{
+			get	{	return m_countRefreshStateChange != 0;	}
+		}
+
+		private void ResumeRefreshStateChange(INestedPanesContainer oldContainer, DockState oldDockState)
+		{
+			ResumeRefreshStateChange();
+			RefreshStateChange(oldContainer, oldDockState);
+		}
+
+		private void RefreshStateChange(INestedPanesContainer oldContainer, DockState oldDockState)
+		{
+			lock (this)
+			{
+				if (IsRefreshStateChangeSuspended)
+					return;
+
+				SuspendRefreshStateChange();
+			}
+
+            DockPanel.SuspendLayout(true);
+
+            IDockContent contentFocused = GetFocusedContent();
+            if (contentFocused != null)
+                DockPanel.SaveFocus();
+			SetParent();
+
+			if (ActiveContent != null)
+				ActiveContent.DockHandler.SetDockState(ActiveContent.DockHandler.IsHidden, DockState, ActiveContent.DockHandler.Pane);
+			foreach (IDockContent content in Contents)
+			{
+				if (content.DockHandler.Pane == this)
+					content.DockHandler.SetDockState(content.DockHandler.IsHidden, DockState, content.DockHandler.Pane);
+			}
+
+			if (oldContainer != null)
+			{
+                Control oldContainerControl = (Control)oldContainer;
+				if (oldContainer.DockState == oldDockState && !oldContainerControl.IsDisposed)
+					oldContainerControl.PerformLayout();
+			}
+			if (DockHelper.IsDockStateAutoHide(oldDockState))
+				DockPanel.RefreshActiveAutoHideContent();
+
+			if (NestedPanesContainer.DockState == DockState)
+				((Control)NestedPanesContainer).PerformLayout();
+			if (DockHelper.IsDockStateAutoHide(DockState))
+				DockPanel.RefreshActiveAutoHideContent();
+
+			if (DockHelper.IsDockStateAutoHide(oldDockState) ||
+				DockHelper.IsDockStateAutoHide(DockState))
+			{
+				DockPanel.RefreshAutoHideStrip();
+				DockPanel.PerformLayout();
+			}
+
+			ResumeRefreshStateChange();
+
+            if (contentFocused != null)
+                contentFocused.DockHandler.Activate();
+
+            DockPanel.ResumeLayout(true, true);
+
+            if (oldDockState != DockState)
+                OnDockStateChanged(EventArgs.Empty);
+		}
+
+        private IDockContent GetFocusedContent()
+        {
+            IDockContent contentFocused = null;
+            foreach (IDockContent content in Contents)
+            {
+                if (content.DockHandler.Form.ContainsFocus)
+                {
+                    contentFocused = content;
+                    break;
+                }
+            }
+
+            return contentFocused;
+        }
+
+		public DockPane DockTo(INestedPanesContainer container)
+		{
+			if (container == null)
+				throw new InvalidOperationException(Strings.DockPane_DockTo_NullContainer);
+
+			DockAlignment alignment;
+			if (container.DockState == DockState.DockLeft || container.DockState == DockState.DockRight)
+				alignment = DockAlignment.Bottom;
+			else
+				alignment = DockAlignment.Right;
+
+			return DockTo(container, container.NestedPanes.GetDefaultPreviousPane(this), alignment, 0.5);
+		}
+
+		public DockPane DockTo(INestedPanesContainer container, DockPane previousPane, DockAlignment alignment, double proportion)
+		{
+			if (container == null)
+				throw new InvalidOperationException(Strings.DockPane_DockTo_NullContainer);
+
+			if (container.IsFloat == this.IsFloat)
+			{
+				InternalAddToDockList(container, previousPane, alignment, proportion);
+				return this;
+			}
+
+			IDockContent firstContent = GetFirstContent(container.DockState);
+			if (firstContent == null)
+				return null;
+
+			DockPane pane;
+			DockPanel.DummyContent.DockPanel = DockPanel;
+			if (container.IsFloat)
+				pane = DockPanel.DockPaneFactory.CreateDockPane(DockPanel.DummyContent, (FloatWindow)container, true);
+			else
+				pane = DockPanel.DockPaneFactory.CreateDockPane(DockPanel.DummyContent, container.DockState, true);
+
+			pane.DockTo(container, previousPane, alignment, proportion);
+			SetVisibleContentsToPane(pane);
+			DockPanel.DummyContent.DockPanel = null;
+
+			return pane;
+		}
+
+		private void SetVisibleContentsToPane(DockPane pane)
+		{
+			SetVisibleContentsToPane(pane, ActiveContent);
+		}
+
+		private void SetVisibleContentsToPane(DockPane pane, IDockContent activeContent)
+		{
+			for (int i=0; i<DisplayingContents.Count; i++)
+			{
+				IDockContent content = DisplayingContents[i];
+				if (content.DockHandler.IsDockStateValid(pane.DockState))
+				{
+					content.DockHandler.Pane = pane;
+					i--;
+				}
+			}
+
+            if (activeContent.DockHandler.Pane == pane)
+			    pane.ActiveContent = activeContent;
+		}
+
+		private void InternalAddToDockList(INestedPanesContainer container, DockPane prevPane, DockAlignment alignment, double proportion)
+		{
+			if ((container.DockState == DockState.Float) != IsFloat)
+				throw new InvalidOperationException(Strings.DockPane_DockTo_InvalidContainer);
+
+			int count = container.NestedPanes.Count;
+			if (container.NestedPanes.Contains(this))
+				count --;
+			if (prevPane == null && count > 0)
+				throw new InvalidOperationException(Strings.DockPane_DockTo_NullPrevPane);
+
+			if (prevPane != null && !container.NestedPanes.Contains(prevPane))
+				throw new InvalidOperationException(Strings.DockPane_DockTo_NoPrevPane);
+
+			if (prevPane == this)
+				throw new InvalidOperationException(Strings.DockPane_DockTo_SelfPrevPane);
+
+			INestedPanesContainer oldContainer = NestedPanesContainer;
+			DockState oldDockState = DockState;
+			container.NestedPanes.Add(this);
+			NestedDockingStatus.SetStatus(container.NestedPanes, prevPane, alignment, proportion);
+
+			if (DockHelper.IsDockWindowState(DockState))
+				m_dockState = container.DockState;
+
+			RefreshStateChange(oldContainer, oldDockState);
+		}
+
+		public void SetNestedDockingProportion(double proportion)
+		{
+			NestedDockingStatus.SetStatus(NestedDockingStatus.NestedPanes, NestedDockingStatus.PreviousPane, NestedDockingStatus.Alignment, proportion);
+			if (NestedPanesContainer != null)
+				((Control)NestedPanesContainer).PerformLayout();
+		}
+
+		public DockPane Float()
+		{
+            DockPanel.SuspendLayout(true);
+
+			IDockContent activeContent = ActiveContent;
+
+			DockPane floatPane = GetFloatPaneFromContents();
+			if (floatPane == null)
+			{
+				IDockContent firstContent = GetFirstContent(DockState.Float);
+                if (firstContent == null)
+                {
+                    DockPanel.ResumeLayout(true, true);
+                    return null;
+                }
+				floatPane = DockPanel.DockPaneFactory.CreateDockPane(firstContent,DockState.Float, true);
+			}
+			SetVisibleContentsToPane(floatPane, activeContent);
+
+            DockPanel.ResumeLayout(true, true);
+			return floatPane;
+		}
+
+		private DockPane GetFloatPaneFromContents()
+		{
+			DockPane floatPane = null;
+			for (int i=0; i<DisplayingContents.Count; i++)
+			{
+				IDockContent content = DisplayingContents[i];
+				if (!content.DockHandler.IsDockStateValid(DockState.Float))
+					continue;
+
+				if (floatPane != null && content.DockHandler.FloatPane != floatPane)
+					return null;
+				else
+					floatPane = content.DockHandler.FloatPane;
+			}
+
+			return floatPane;
+		}
+
+		private IDockContent GetFirstContent(DockState dockState)
+		{
+			for (int i=0; i<DisplayingContents.Count; i++)
+			{
+				IDockContent content = DisplayingContents[i];
+				if (content.DockHandler.IsDockStateValid(dockState))
+					return content;
+			}
+			return null;
+		}
+
+		public void RestoreToPanel()
+		{
+            DockPanel.SuspendLayout(true);
+
+			IDockContent activeContent = DockPanel.ActiveContent;
+
+			for (int i=DisplayingContents.Count-1; i>=0; i--)
+			{
+				IDockContent content = DisplayingContents[i];
+                if (content.DockHandler.CheckDockState(false) != DockState.Unknown)
+				    content.DockHandler.IsFloat = false;
+			}
+
+            DockPanel.ResumeLayout(true, true);
+		}
+
+        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
+        protected override void WndProc(ref Message m)
+        {
+            if (m.Msg == (int)Win32.Msgs.WM_MOUSEACTIVATE)
+                Activate();
+
+            base.WndProc(ref m);
+        }
+
+        #region IDockDragSource Members
+
+        #region IDragSource Members
+
+        Control IDragSource.DragControl
+        {
+            get { return this; }
+        }
+
+        #endregion
+
+        bool IDockDragSource.IsDockStateValid(DockState dockState)
+        {
+            return IsDockStateValid(dockState);
+        }
+
+        bool IDockDragSource.CanDockTo(DockPane pane)
+        {
+            if (!IsDockStateValid(pane.DockState))
+                return false;
+
+            if (pane == this)
+                return false;
+
+            return true;
+        }
+
+        Rectangle IDockDragSource.BeginDrag(Point ptMouse)
+        {
+            Point location = PointToScreen(new Point(0, 0));
+            Size size;
+
+            DockPane floatPane = ActiveContent.DockHandler.FloatPane;
+            if (DockState == DockState.Float || floatPane == null || floatPane.FloatWindow.NestedPanes.Count != 1)
+                size = DockPanel.DefaultFloatWindowSize;
+            else
+                size = floatPane.FloatWindow.Size;
+
+            if (ptMouse.X > location.X + size.Width)
+                location.X += ptMouse.X - (location.X + size.Width) + Measures.SplitterSize;
+
+            return new Rectangle(location, size);
+        }
+
+        public void FloatAt(Rectangle floatWindowBounds)
+        {
+            if (FloatWindow == null || FloatWindow.NestedPanes.Count != 1)
+                FloatWindow = DockPanel.FloatWindowFactory.CreateFloatWindow(DockPanel, this, floatWindowBounds);
+            else
+                FloatWindow.Bounds = floatWindowBounds;
+
+            DockState = DockState.Float;
+        }
+
+        public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex)
+        {
+            if (dockStyle == DockStyle.Fill)
+            {
+                IDockContent activeContent = ActiveContent;
+                for (int i = Contents.Count - 1; i >= 0; i--)
+                {
+                    IDockContent c = Contents[i];
+                    if (c.DockHandler.DockState == DockState)
+                    {
+                        c.DockHandler.Pane = pane;
+                        if (contentIndex != -1)
+                            pane.SetContentIndex(c, contentIndex);
+                    }
+                }
+                pane.ActiveContent = activeContent;
+            }
+            else
+            {
+                if (dockStyle == DockStyle.Left)
+                    DockTo(pane.NestedPanesContainer, pane, DockAlignment.Left, 0.5);
+                else if (dockStyle == DockStyle.Right)
+                    DockTo(pane.NestedPanesContainer, pane, DockAlignment.Right, 0.5);
+                else if (dockStyle == DockStyle.Top)
+                    DockTo(pane.NestedPanesContainer, pane, DockAlignment.Top, 0.5);
+                else if (dockStyle == DockStyle.Bottom)
+                    DockTo(pane.NestedPanesContainer, pane, DockAlignment.Bottom, 0.5);
+
+                DockState = pane.DockState;
+            }
+        }
+
+        public void DockTo(DockPanel panel, DockStyle dockStyle)
+        {
+            if (panel != DockPanel)
+                throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel");
+
+            if (dockStyle == DockStyle.Top)
+                DockState = DockState.DockTop;
+            else if (dockStyle == DockStyle.Bottom)
+                DockState = DockState.DockBottom;
+            else if (dockStyle == DockStyle.Left)
+                DockState = DockState.DockLeft;
+            else if (dockStyle == DockStyle.Right)
+                DockState = DockState.DockRight;
+            else if (dockStyle == DockStyle.Fill)
+                DockState = DockState.Document;
+        }
+
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneCaptionBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneCaptionBase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneCaptionBase.cs	(revision 2645)
@@ -0,0 +1,100 @@
+using System;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public abstract class DockPaneCaptionBase : Control
+	{
+		protected internal DockPaneCaptionBase(DockPane pane)
+		{
+			m_dockPane = pane;
+
+			SetStyle(ControlStyles.OptimizedDoubleBuffer |
+                ControlStyles.ResizeRedraw |
+                ControlStyles.UserPaint |
+                ControlStyles.AllPaintingInWmPaint, true);
+			SetStyle(ControlStyles.Selectable, false);
+		}
+
+		private DockPane m_dockPane;
+		protected DockPane DockPane
+		{
+			get	{	return m_dockPane;	}
+		}
+
+		protected DockPane.AppearanceStyle Appearance
+		{
+			get	{	return DockPane.Appearance;	}
+		}
+
+        protected bool HasTabPageContextMenu
+        {
+            get { return DockPane.HasTabPageContextMenu; }
+        }
+
+        protected void ShowTabPageContextMenu(Point position)
+        {
+            DockPane.ShowTabPageContextMenu(this, position);
+        }
+
+        protected override void OnMouseUp(MouseEventArgs e)
+        {
+            base.OnMouseUp(e);
+
+            if (e.Button == MouseButtons.Right)
+                ShowTabPageContextMenu(new Point(e.X, e.Y));
+        }
+
+        protected override void OnMouseDown(MouseEventArgs e)
+        {
+            base.OnMouseDown(e);
+
+            if (e.Button == MouseButtons.Left &&
+			    DockPane.DockPanel.AllowEndUserDocking &&
+                DockPane.AllowDockDragAndDrop &&
+				!DockHelper.IsDockStateAutoHide(DockPane.DockState) &&
+                DockPane.ActiveContent != null)
+				DockPane.DockPanel.BeginDrag(DockPane);
+        }
+
+        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]         
+        protected override void WndProc(ref Message m)
+        {
+            if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK)
+            {
+                if (DockHelper.IsDockStateAutoHide(DockPane.DockState))
+                {
+                    DockPane.DockPanel.ActiveAutoHideContent = null;
+                    return;
+                }
+
+                if (DockPane.IsFloat)
+                    DockPane.RestoreToPanel();
+                else
+                    DockPane.Float();
+            }
+            base.WndProc(ref m);
+        }
+
+		internal void RefreshChanges()
+		{
+            if (IsDisposed)
+                return;
+
+			OnRefreshChanges();
+		}
+
+        protected virtual void OnRightToLeftLayoutChanged()
+        {
+        }
+
+		protected virtual void OnRefreshChanges()
+		{
+		}
+
+		protected internal abstract int MeasureHeight();
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneCollection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneCollection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneCollection.cs	(revision 2645)
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public class DockPaneCollection : ReadOnlyCollection<DockPane>
+	{
+        internal DockPaneCollection()
+            : base(new List<DockPane>())
+        {
+        }
+
+		internal int Add(DockPane pane)
+		{
+			if (Items.Contains(pane))
+				return Items.IndexOf(pane);
+
+			Items.Add(pane);
+            return Count - 1;
+		}
+
+		internal void AddAt(DockPane pane, int index)
+		{
+			if (index < 0 || index > Items.Count - 1)
+				return;
+			
+			if (Contains(pane))
+				return;
+
+			Items.Insert(index, pane);
+		}
+
+		internal void Dispose()
+		{
+			for (int i=Count - 1; i>=0; i--)
+				this[i].Close();
+		}
+
+		internal void Remove(DockPane pane)
+		{
+			Items.Remove(pane);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneStripBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneStripBase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPaneStripBase.cs	(revision 2645)
@@ -0,0 +1,252 @@
+using System;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Collections;
+using System.Collections.Generic;
+using System.Security.Permissions;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public abstract class DockPaneStripBase : Control
+	{
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]        
+        protected internal class Tab : IDisposable
+        {
+            private IDockContent m_content;
+
+            public Tab(IDockContent content)
+            {
+                m_content = content;
+            }
+
+            ~Tab()
+            {
+                Dispose(false);
+            }
+
+            public IDockContent Content
+            {
+                get { return m_content; }
+            }
+
+            public Form ContentForm
+            {
+                get { return m_content as Form; }
+            }
+
+            public void Dispose()
+            {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
+
+            protected virtual void Dispose(bool disposing)
+            {
+            }
+        }
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]        
+        protected sealed class TabCollection : IEnumerable<Tab>
+        {
+            #region IEnumerable Members
+            IEnumerator<Tab> IEnumerable<Tab>.GetEnumerator()
+            {
+                for (int i = 0; i < Count; i++)
+                    yield return this[i];
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                for (int i = 0; i < Count; i++)
+                    yield return this[i];
+            }
+            #endregion
+
+            internal TabCollection(DockPane pane)
+            {
+                m_dockPane = pane;
+            }
+
+            private DockPane m_dockPane;
+            public DockPane DockPane
+            {
+                get { return m_dockPane; }
+            }
+
+            public int Count
+            {
+                get { return DockPane.DisplayingContents.Count; }
+            }
+
+            public Tab this[int index]
+            {
+                get
+                {
+                    IDockContent content = DockPane.DisplayingContents[index];
+                    if (content == null)
+                        throw (new ArgumentOutOfRangeException("index"));
+                    return content.DockHandler.GetTab(DockPane.TabStripControl);
+                }
+            }
+
+            public bool Contains(Tab tab)
+            {
+                return (IndexOf(tab) != -1);
+            }
+
+            public bool Contains(IDockContent content)
+            {
+                return (IndexOf(content) != -1);
+            }
+
+            public int IndexOf(Tab tab)
+            {
+                if (tab == null)
+                    return -1;
+
+                return DockPane.DisplayingContents.IndexOf(tab.Content);
+            }
+
+            public int IndexOf(IDockContent content)
+            {
+                return DockPane.DisplayingContents.IndexOf(content);
+            }
+        }
+
+		protected DockPaneStripBase(DockPane pane)
+		{
+			m_dockPane = pane;
+
+			SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+			SetStyle(ControlStyles.Selectable, false);
+            AllowDrop = true;
+		}
+
+		private DockPane m_dockPane;
+		protected DockPane DockPane
+		{
+			get	{	return m_dockPane;	}
+		}
+
+		protected DockPane.AppearanceStyle Appearance
+		{
+			get	{	return DockPane.Appearance;	}
+		}
+
+        private TabCollection m_tabs = null;
+		protected TabCollection Tabs
+		{
+			get
+            {
+                if (m_tabs == null)
+                    m_tabs = new TabCollection(DockPane);
+
+                return m_tabs;
+            }
+		}
+
+		internal void RefreshChanges()
+		{
+            if (IsDisposed)
+                return;
+
+			OnRefreshChanges();
+		}
+
+		protected virtual void OnRefreshChanges()
+		{
+		}
+
+		protected internal abstract int MeasureHeight();
+
+		protected internal abstract void EnsureTabVisible(IDockContent content);
+
+		protected int HitTest()
+		{
+			return HitTest(PointToClient(Control.MousePosition));
+		}
+
+		protected internal abstract int HitTest(Point point);
+
+		protected internal abstract GraphicsPath GetOutline(int index);
+
+        protected internal virtual Tab CreateTab(IDockContent content)
+        {
+            return new Tab(content);
+        }
+
+        protected override void OnMouseDown(MouseEventArgs e)
+        {
+            base.OnMouseDown(e);
+
+            int index = HitTest();
+            if (index != -1)
+            {
+                IDockContent content = Tabs[index].Content;
+                if (DockPane.ActiveContent != content)
+                    DockPane.ActiveContent = content;
+            }
+
+            if (e.Button == MouseButtons.Left)
+            {
+                if (DockPane.DockPanel.AllowEndUserDocking && DockPane.AllowDockDragAndDrop && DockPane.ActiveContent.DockHandler.AllowEndUserDocking)
+                    DockPane.DockPanel.BeginDrag(DockPane.ActiveContent.DockHandler);
+            }
+        }
+
+        protected bool HasTabPageContextMenu
+        {
+            get { return DockPane.HasTabPageContextMenu; }
+        }
+
+        protected void ShowTabPageContextMenu(Point position)
+        {
+            DockPane.ShowTabPageContextMenu(this, position);
+        }
+
+        protected override void OnMouseUp(MouseEventArgs e)
+        {
+            base.OnMouseUp(e);
+
+            if (e.Button == MouseButtons.Right)
+                ShowTabPageContextMenu(new Point(e.X, e.Y));
+        }
+
+        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
+		protected override void WndProc(ref Message m)
+		{
+			if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK)
+			{
+				base.WndProc(ref m);
+
+				int index = HitTest();
+				if (DockPane.DockPanel.AllowEndUserDocking && index != -1)
+				{
+					IDockContent content = Tabs[index].Content;
+                    if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown)
+					    content.DockHandler.IsFloat = !content.DockHandler.IsFloat;	
+				}
+
+				return;
+			}
+
+			base.WndProc(ref m);
+			return;
+		}
+
+        protected override void OnDragOver(DragEventArgs drgevent)
+        {
+            base.OnDragOver(drgevent);
+
+            int index = HitTest();
+            if (index != -1)
+            {
+                IDockContent content = Tabs[index].Content;
+                if (DockPane.ActiveContent != content)
+                    DockPane.ActiveContent = content;
+            }
+        }
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.AutoHideWindow.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.AutoHideWindow.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.AutoHideWindow.cs	(revision 2645)
@@ -0,0 +1,612 @@
+using System;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPanel
+    {
+        private class AutoHideWindowControl : Panel, ISplitterDragSource
+        {
+            private class SplitterControl : SplitterBase
+            {
+                public SplitterControl(AutoHideWindowControl autoHideWindow)
+                {
+                    m_autoHideWindow = autoHideWindow;
+                }
+
+                private AutoHideWindowControl m_autoHideWindow;
+                private AutoHideWindowControl AutoHideWindow
+                {
+                    get { return m_autoHideWindow; }
+                }
+
+                protected override int SplitterSize
+                {
+                    get { return Measures.SplitterSize; }
+                }
+
+                protected override void StartDrag()
+                {
+        			AutoHideWindow.DockPanel.BeginDrag(AutoHideWindow, AutoHideWindow.RectangleToScreen(Bounds));
+                }
+            }
+
+            #region consts
+            private const int ANIMATE_TIME = 100;	// in mini-seconds
+            #endregion
+
+            private Timer m_timerMouseTrack;
+            private SplitterControl m_splitter;
+
+            public AutoHideWindowControl(DockPanel dockPanel)
+            {
+                m_dockPanel = dockPanel;
+
+                m_timerMouseTrack = new Timer();
+                m_timerMouseTrack.Tick += new EventHandler(TimerMouseTrack_Tick);
+
+                Visible = false;
+                m_splitter = new SplitterControl(this);
+                Controls.Add(m_splitter);
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+                if (disposing)
+                {
+                    m_timerMouseTrack.Dispose();
+                }
+                base.Dispose(disposing);
+            }
+
+            private DockPanel m_dockPanel = null;
+            public DockPanel DockPanel
+            {
+                get { return m_dockPanel; }
+            }
+
+            private DockPane m_activePane = null;
+            public DockPane ActivePane
+            {
+                get { return m_activePane; }
+            }
+            private void SetActivePane()
+            {
+                DockPane value = (ActiveContent == null ? null : ActiveContent.DockHandler.Pane);
+
+                if (value == m_activePane)
+                    return;
+
+                m_activePane = value;
+            }
+
+            private IDockContent m_activeContent = null;
+            public IDockContent ActiveContent
+            {
+                get { return m_activeContent; }
+                set
+                {
+                    if (value == m_activeContent)
+                        return;
+
+                    if (value != null)
+                    {
+                        if (!DockHelper.IsDockStateAutoHide(value.DockHandler.DockState) || value.DockHandler.DockPanel != DockPanel)
+                            throw (new InvalidOperationException(Strings.DockPanel_ActiveAutoHideContent_InvalidValue));
+                    }
+
+                    DockPanel.SuspendLayout();
+
+                    if (m_activeContent != null)
+                    {
+                        if (m_activeContent.DockHandler.Form.ContainsFocus)
+                            DockPanel.ContentFocusManager.GiveUpFocus(m_activeContent);
+                        AnimateWindow(false);
+                    }
+
+                    m_activeContent = value;
+                    SetActivePane();
+                    if (ActivePane != null)
+                        ActivePane.ActiveContent = m_activeContent;
+
+                    if (m_activeContent != null)
+                        AnimateWindow(true);
+
+                    DockPanel.ResumeLayout();
+                    DockPanel.RefreshAutoHideStrip();
+
+                    SetTimerMouseTrack();
+                }
+            }
+
+            public DockState DockState
+            {
+                get { return ActiveContent == null ? DockState.Unknown : ActiveContent.DockHandler.DockState; }
+            }
+
+            private bool m_flagAnimate = true;
+            private bool FlagAnimate
+            {
+                get { return m_flagAnimate; }
+                set { m_flagAnimate = value; }
+            }
+
+            private bool m_flagDragging = false;
+            internal bool FlagDragging
+            {
+                get { return m_flagDragging; }
+                set
+                {
+                    if (m_flagDragging == value)
+                        return;
+
+                    m_flagDragging = value;
+                    SetTimerMouseTrack();
+                }
+            }
+
+            private void AnimateWindow(bool show)
+            {
+                if (!FlagAnimate && Visible != show)
+                {
+                    Visible = show;
+                    return;
+                }
+
+                Parent.SuspendLayout();
+
+                Rectangle rectSource = GetRectangle(!show);
+                Rectangle rectTarget = GetRectangle(show);
+                int dxLoc, dyLoc;
+                int dWidth, dHeight;
+                dxLoc = dyLoc = dWidth = dHeight = 0;
+                if (DockState == DockState.DockTopAutoHide)
+                    dHeight = show ? 1 : -1;
+                else if (DockState == DockState.DockLeftAutoHide)
+                    dWidth = show ? 1 : -1;
+                else if (DockState == DockState.DockRightAutoHide)
+                {
+                    dxLoc = show ? -1 : 1;
+                    dWidth = show ? 1 : -1;
+                }
+                else if (DockState == DockState.DockBottomAutoHide)
+                {
+                    dyLoc = (show ? -1 : 1);
+                    dHeight = (show ? 1 : -1);
+                }
+
+                if (show)
+                {
+                    Bounds = DockPanel.GetAutoHideWindowBounds(new Rectangle(-rectTarget.Width, -rectTarget.Height, rectTarget.Width, rectTarget.Height));
+                    if (Visible == false)
+                        Visible = true;
+                    PerformLayout();
+                }
+
+                SuspendLayout();
+
+                LayoutAnimateWindow(rectSource);
+                if (Visible == false)
+                    Visible = true;
+
+                int speedFactor = 1;
+                int totalPixels = (rectSource.Width != rectTarget.Width) ?
+                    Math.Abs(rectSource.Width - rectTarget.Width) :
+                    Math.Abs(rectSource.Height - rectTarget.Height);
+                int remainPixels = totalPixels;
+                DateTime startingTime = DateTime.Now;
+                while (rectSource != rectTarget)
+                {
+                    DateTime startPerMove = DateTime.Now;
+
+                    rectSource.X += dxLoc * speedFactor;
+                    rectSource.Y += dyLoc * speedFactor;
+                    rectSource.Width += dWidth * speedFactor;
+                    rectSource.Height += dHeight * speedFactor;
+                    if (Math.Sign(rectTarget.X - rectSource.X) != Math.Sign(dxLoc))
+                        rectSource.X = rectTarget.X;
+                    if (Math.Sign(rectTarget.Y - rectSource.Y) != Math.Sign(dyLoc))
+                        rectSource.Y = rectTarget.Y;
+                    if (Math.Sign(rectTarget.Width - rectSource.Width) != Math.Sign(dWidth))
+                        rectSource.Width = rectTarget.Width;
+                    if (Math.Sign(rectTarget.Height - rectSource.Height) != Math.Sign(dHeight))
+                        rectSource.Height = rectTarget.Height;
+
+                    LayoutAnimateWindow(rectSource);
+                    if (Parent != null)
+                        Parent.Update();
+
+                    remainPixels -= speedFactor;
+
+                    while (true)
+                    {
+                        TimeSpan time = new TimeSpan(0, 0, 0, 0, ANIMATE_TIME);
+                        TimeSpan elapsedPerMove = DateTime.Now - startPerMove;
+                        TimeSpan elapsedTime = DateTime.Now - startingTime;
+                        if (((int)((time - elapsedTime).TotalMilliseconds)) <= 0)
+                        {
+                            speedFactor = remainPixels;
+                            break;
+                        }
+                        else
+                            speedFactor = remainPixels * (int)elapsedPerMove.TotalMilliseconds / (int)((time - elapsedTime).TotalMilliseconds);
+                        if (speedFactor >= 1)
+                            break;
+                    }
+                }
+                ResumeLayout();
+                Parent.ResumeLayout();
+            }
+
+            private void LayoutAnimateWindow(Rectangle rect)
+            {
+                Bounds = DockPanel.GetAutoHideWindowBounds(rect);
+
+                Rectangle rectClient = ClientRectangle;
+
+                if (DockState == DockState.DockLeftAutoHide)
+                    ActivePane.Location = new Point(rectClient.Right - 2 - Measures.SplitterSize - ActivePane.Width, ActivePane.Location.Y);
+                else if (DockState == DockState.DockTopAutoHide)
+                    ActivePane.Location = new Point(ActivePane.Location.X, rectClient.Bottom - 2 - Measures.SplitterSize - ActivePane.Height);
+            }
+
+            private Rectangle GetRectangle(bool show)
+            {
+                if (DockState == DockState.Unknown)
+                    return Rectangle.Empty;
+
+                Rectangle rect = DockPanel.AutoHideWindowRectangle;
+
+                if (show)
+                    return rect;
+
+                if (DockState == DockState.DockLeftAutoHide)
+                    rect.Width = 0;
+                else if (DockState == DockState.DockRightAutoHide)
+                {
+                    rect.X += rect.Width;
+                    rect.Width = 0;
+                }
+                else if (DockState == DockState.DockTopAutoHide)
+                    rect.Height = 0;
+                else
+                {
+                    rect.Y += rect.Height;
+                    rect.Height = 0;
+                }
+
+                return rect;
+            }
+
+            private void SetTimerMouseTrack()
+            {
+                if (ActivePane == null || ActivePane.IsActivated || FlagDragging)
+                {
+                    m_timerMouseTrack.Enabled = false;
+                    return;
+                }
+
+                // start the timer
+                int hovertime = SystemInformation.MouseHoverTime ;
+
+                // assign a default value 400 in case of setting Timer.Interval invalid value exception
+                if (hovertime <= 0)
+                    hovertime = 400;
+
+                m_timerMouseTrack.Interval = 2 * (int)hovertime;
+                m_timerMouseTrack.Enabled = true;
+            }
+
+            protected virtual Rectangle DisplayingRectangle
+            {
+                get
+                {
+                    Rectangle rect = ClientRectangle;
+
+                    // exclude the border and the splitter
+                    if (DockState == DockState.DockBottomAutoHide)
+                    {
+                        rect.Y += 2 + Measures.SplitterSize;
+                        rect.Height -= 2 + Measures.SplitterSize;
+                    }
+                    else if (DockState == DockState.DockRightAutoHide)
+                    {
+                        rect.X += 2 + Measures.SplitterSize;
+                        rect.Width -= 2 + Measures.SplitterSize;
+                    }
+                    else if (DockState == DockState.DockTopAutoHide)
+                        rect.Height -= 2 + Measures.SplitterSize;
+                    else if (DockState == DockState.DockLeftAutoHide)
+                        rect.Width -= 2 + Measures.SplitterSize;
+
+                    return rect;
+                }
+            }
+
+            protected override void OnLayout(LayoutEventArgs levent)
+            {
+                DockPadding.All = 0;
+                if (DockState == DockState.DockLeftAutoHide)
+                {
+                    DockPadding.Right = 2;
+                    m_splitter.Dock = DockStyle.Right;
+                }
+                else if (DockState == DockState.DockRightAutoHide)
+                {
+                    DockPadding.Left = 2;
+                    m_splitter.Dock = DockStyle.Left;
+                }
+                else if (DockState == DockState.DockTopAutoHide)
+                {
+                    DockPadding.Bottom = 2;
+                    m_splitter.Dock = DockStyle.Bottom;
+                }
+                else if (DockState == DockState.DockBottomAutoHide)
+                {
+                    DockPadding.Top = 2;
+                    m_splitter.Dock = DockStyle.Top;
+                }
+
+                Rectangle rectDisplaying = DisplayingRectangle;
+                Rectangle rectHidden = new Rectangle(-rectDisplaying.Width, rectDisplaying.Y, rectDisplaying.Width, rectDisplaying.Height);
+                foreach (Control c in Controls)
+                {
+                    DockPane pane = c as DockPane;
+                    if (pane == null)
+                        continue;
+                    
+                    
+                    if (pane == ActivePane)
+                        pane.Bounds = rectDisplaying;
+                    else
+                        pane.Bounds = rectHidden;
+                }
+
+                base.OnLayout(levent);
+            }
+
+            protected override void OnPaint(PaintEventArgs e)
+            {
+                // Draw the border
+                Graphics g = e.Graphics;
+
+                if (DockState == DockState.DockBottomAutoHide)
+                    g.DrawLine(SystemPens.ControlLightLight, 0, 1, ClientRectangle.Right, 1);
+                else if (DockState == DockState.DockRightAutoHide)
+                    g.DrawLine(SystemPens.ControlLightLight, 1, 0, 1, ClientRectangle.Bottom);
+                else if (DockState == DockState.DockTopAutoHide)
+                {
+                    g.DrawLine(SystemPens.ControlDark, 0, ClientRectangle.Height - 2, ClientRectangle.Right, ClientRectangle.Height - 2);
+                    g.DrawLine(SystemPens.ControlDarkDark, 0, ClientRectangle.Height - 1, ClientRectangle.Right, ClientRectangle.Height - 1);
+                }
+                else if (DockState == DockState.DockLeftAutoHide)
+                {
+                    g.DrawLine(SystemPens.ControlDark, ClientRectangle.Width - 2, 0, ClientRectangle.Width - 2, ClientRectangle.Bottom);
+                    g.DrawLine(SystemPens.ControlDarkDark, ClientRectangle.Width - 1, 0, ClientRectangle.Width - 1, ClientRectangle.Bottom);
+                }
+
+                base.OnPaint(e);
+            }
+
+            public void RefreshActiveContent()
+            {
+                if (ActiveContent == null)
+                    return;
+
+                if (!DockHelper.IsDockStateAutoHide(ActiveContent.DockHandler.DockState))
+                {
+                    FlagAnimate = false;
+                    ActiveContent = null;
+                    FlagAnimate = true;
+                }
+            }
+
+            public void RefreshActivePane()
+            {
+                SetTimerMouseTrack();
+            }
+
+            private void TimerMouseTrack_Tick(object sender, EventArgs e)
+            {
+                if (IsDisposed)
+                    return;
+
+                if (ActivePane == null || ActivePane.IsActivated)
+                {
+                    m_timerMouseTrack.Enabled = false;
+                    return;
+                }
+
+                DockPane pane = ActivePane;
+                Point ptMouseInAutoHideWindow = PointToClient(Control.MousePosition);
+                Point ptMouseInDockPanel = DockPanel.PointToClient(Control.MousePosition);
+
+                Rectangle rectTabStrip = DockPanel.GetTabStripRectangle(pane.DockState);
+
+                if (!ClientRectangle.Contains(ptMouseInAutoHideWindow) && !rectTabStrip.Contains(ptMouseInDockPanel))
+                {
+                    ActiveContent = null;
+                    m_timerMouseTrack.Enabled = false;
+                }
+            }
+
+            #region ISplitterDragSource Members
+
+            void ISplitterDragSource.BeginDrag(Rectangle rectSplitter)
+            {
+                FlagDragging = true;
+            }
+
+            void ISplitterDragSource.EndDrag()
+            {
+                FlagDragging = false;
+            }
+
+            bool ISplitterDragSource.IsVertical
+            {
+                get { return (DockState == DockState.DockLeftAutoHide || DockState == DockState.DockRightAutoHide); }
+            }
+
+            Rectangle ISplitterDragSource.DragLimitBounds
+            {
+                get
+                {
+                    Rectangle rectLimit = DockPanel.DockArea;
+
+                    if ((this as ISplitterDragSource).IsVertical)
+                    {
+                        rectLimit.X += MeasurePane.MinSize;
+                        rectLimit.Width -= 2 * MeasurePane.MinSize;
+                    }
+                    else
+                    {
+                        rectLimit.Y += MeasurePane.MinSize;
+                        rectLimit.Height -= 2 * MeasurePane.MinSize;
+                    }
+
+                    return DockPanel.RectangleToScreen(rectLimit);
+                }
+            }
+
+            void ISplitterDragSource.MoveSplitter(int offset)
+            {
+                Rectangle rectDockArea = DockPanel.DockArea;
+                IDockContent content = ActiveContent;
+                if (DockState == DockState.DockLeftAutoHide && rectDockArea.Width > 0)
+                {
+                    if (content.DockHandler.AutoHidePortion < 1)
+                        content.DockHandler.AutoHidePortion += ((double)offset) / (double)rectDockArea.Width;
+                    else
+                        content.DockHandler.AutoHidePortion = Width + offset;
+                }
+                else if (DockState == DockState.DockRightAutoHide && rectDockArea.Width > 0)
+                {
+                    if (content.DockHandler.AutoHidePortion < 1)
+                        content.DockHandler.AutoHidePortion -= ((double)offset) / (double)rectDockArea.Width;
+                    else
+                        content.DockHandler.AutoHidePortion = Width - offset;
+                }
+                else if (DockState == DockState.DockBottomAutoHide && rectDockArea.Height > 0)
+                {
+                    if (content.DockHandler.AutoHidePortion < 1)
+                        content.DockHandler.AutoHidePortion -= ((double)offset) / (double)rectDockArea.Height;
+                    else
+                        content.DockHandler.AutoHidePortion = Height - offset;
+                }
+                else if (DockState == DockState.DockTopAutoHide && rectDockArea.Height > 0)
+                {
+                    if (content.DockHandler.AutoHidePortion < 1)
+                        content.DockHandler.AutoHidePortion += ((double)offset) / (double)rectDockArea.Height;
+                    else
+                        content.DockHandler.AutoHidePortion = Height + offset;
+                }
+            }
+
+            #region IDragSource Members
+
+            Control IDragSource.DragControl
+            {
+                get { return this; }
+            }
+
+            #endregion
+
+            #endregion
+        }
+
+        private AutoHideWindowControl AutoHideWindow
+        {
+            get { return m_autoHideWindow; }
+        }
+
+        internal Control AutoHideControl
+        {
+            get { return m_autoHideWindow; }
+        }
+
+        internal void RefreshActiveAutoHideContent()
+        {
+            AutoHideWindow.RefreshActiveContent();
+        }
+
+        internal Rectangle AutoHideWindowRectangle
+        {
+            get
+            {
+                DockState state = AutoHideWindow.DockState;
+                Rectangle rectDockArea = DockArea;
+                if (ActiveAutoHideContent == null)
+                    return Rectangle.Empty;
+
+                if (Parent == null)
+                    return Rectangle.Empty;
+
+                Rectangle rect = Rectangle.Empty;
+                double autoHideSize = ActiveAutoHideContent.DockHandler.AutoHidePortion;
+                if (state == DockState.DockLeftAutoHide)
+                {
+                    if (autoHideSize < 1)
+                        autoHideSize = rectDockArea.Width * autoHideSize;
+                    if (autoHideSize > rectDockArea.Width - MeasurePane.MinSize)
+                        autoHideSize = rectDockArea.Width - MeasurePane.MinSize;
+                    rect.X = rectDockArea.X;
+                    rect.Y = rectDockArea.Y;
+                    rect.Width = (int)autoHideSize;
+                    rect.Height = rectDockArea.Height;
+                }
+                else if (state == DockState.DockRightAutoHide)
+                {
+                    if (autoHideSize < 1)
+                        autoHideSize = rectDockArea.Width * autoHideSize;
+                    if (autoHideSize > rectDockArea.Width - MeasurePane.MinSize)
+                        autoHideSize = rectDockArea.Width - MeasurePane.MinSize;
+                    rect.X = rectDockArea.X + rectDockArea.Width - (int)autoHideSize;
+                    rect.Y = rectDockArea.Y;
+                    rect.Width = (int)autoHideSize;
+                    rect.Height = rectDockArea.Height;
+                }
+                else if (state == DockState.DockTopAutoHide)
+                {
+                    if (autoHideSize < 1)
+                        autoHideSize = rectDockArea.Height * autoHideSize;
+                    if (autoHideSize > rectDockArea.Height - MeasurePane.MinSize)
+                        autoHideSize = rectDockArea.Height - MeasurePane.MinSize;
+                    rect.X = rectDockArea.X;
+                    rect.Y = rectDockArea.Y;
+                    rect.Width = rectDockArea.Width;
+                    rect.Height = (int)autoHideSize;
+                }
+                else if (state == DockState.DockBottomAutoHide)
+                {
+                    if (autoHideSize < 1)
+                        autoHideSize = rectDockArea.Height * autoHideSize;
+                    if (autoHideSize > rectDockArea.Height - MeasurePane.MinSize)
+                        autoHideSize = rectDockArea.Height - MeasurePane.MinSize;
+                    rect.X = rectDockArea.X;
+                    rect.Y = rectDockArea.Y + rectDockArea.Height - (int)autoHideSize;
+                    rect.Width = rectDockArea.Width;
+                    rect.Height = (int)autoHideSize;
+                }
+
+                return rect;
+            }
+        }
+
+        internal Rectangle GetAutoHideWindowBounds(Rectangle rectAutoHideWindow)
+        {
+            if (DocumentStyle == DocumentStyle.SystemMdi ||
+                DocumentStyle == DocumentStyle.DockingMdi)
+                return (Parent == null) ? Rectangle.Empty : Parent.RectangleToClient(RectangleToScreen(rectAutoHideWindow));
+            else
+                return rectAutoHideWindow;
+        }
+
+        internal void RefreshAutoHideStrip()
+        {
+            AutoHideStripControl.RefreshChanges();
+        }
+
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.DockDragHandler.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.DockDragHandler.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.DockDragHandler.cs	(revision 2645)
@@ -0,0 +1,814 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPanel
+    {
+        private sealed class DockDragHandler : DragHandler
+        {
+            private class DockIndicator : DragForm
+            {
+                #region IHitTest
+                private interface IHitTest
+                {
+                    DockStyle HitTest(Point pt);
+                    DockStyle Status { get;	set;	}
+                }
+                #endregion
+
+                #region PanelIndicator
+                private class PanelIndicator : PictureBox, IHitTest
+                {
+                    private static Image _imagePanelLeft = Resources.DockIndicator_PanelLeft;
+                    private static Image _imagePanelRight = Resources.DockIndicator_PanelRight;
+                    private static Image _imagePanelTop = Resources.DockIndicator_PanelTop;
+                    private static Image _imagePanelBottom = Resources.DockIndicator_PanelBottom;
+                    private static Image _imagePanelFill = Resources.DockIndicator_PanelFill;
+                    private static Image _imagePanelLeftActive = Resources.DockIndicator_PanelLeft_Active;
+                    private static Image _imagePanelRightActive = Resources.DockIndicator_PanelRight_Active;
+                    private static Image _imagePanelTopActive = Resources.DockIndicator_PanelTop_Active;
+                    private static Image _imagePanelBottomActive = Resources.DockIndicator_PanelBottom_Active;
+                    private static Image _imagePanelFillActive = Resources.DockIndicator_PanelFill_Active;
+
+                    public PanelIndicator(DockStyle dockStyle)
+                    {
+                        m_dockStyle = dockStyle;
+                        SizeMode = PictureBoxSizeMode.AutoSize;
+                        Image = ImageInactive;
+                    }
+
+                    private DockStyle m_dockStyle;
+                    private DockStyle DockStyle
+                    {
+                        get { return m_dockStyle; }
+                    }
+
+                    private DockStyle m_status;
+                    public DockStyle Status
+                    {
+                        get { return m_status; }
+                        set
+                        {
+                            if (value != DockStyle && value != DockStyle.None)
+                                throw new InvalidEnumArgumentException();
+
+                            if (m_status == value)
+                                return;
+
+                            m_status = value;
+                            IsActivated = (m_status != DockStyle.None);
+                        }
+                    }
+
+                    private Image ImageInactive
+                    {
+                        get
+                        {
+                            if (DockStyle == DockStyle.Left)
+                                return _imagePanelLeft;
+                            else if (DockStyle == DockStyle.Right)
+                                return _imagePanelRight;
+                            else if (DockStyle == DockStyle.Top)
+                                return _imagePanelTop;
+                            else if (DockStyle == DockStyle.Bottom)
+                                return _imagePanelBottom;
+                            else if (DockStyle == DockStyle.Fill)
+                                return _imagePanelFill;
+                            else
+                                return null;
+                        }
+                    }
+
+                    private Image ImageActive
+                    {
+                        get
+                        {
+                            if (DockStyle == DockStyle.Left)
+                                return _imagePanelLeftActive;
+                            else if (DockStyle == DockStyle.Right)
+                                return _imagePanelRightActive;
+                            else if (DockStyle == DockStyle.Top)
+                                return _imagePanelTopActive;
+                            else if (DockStyle == DockStyle.Bottom)
+                                return _imagePanelBottomActive;
+                            else if (DockStyle == DockStyle.Fill)
+                                return _imagePanelFillActive;
+                            else
+                                return null;
+                        }
+                    }
+
+                    private bool m_isActivated = false;
+                    private bool IsActivated
+                    {
+                        get { return m_isActivated; }
+                        set
+                        {
+                            m_isActivated = value;
+                            Image = IsActivated ? ImageActive : ImageInactive;
+                        }
+                    }
+
+                    public DockStyle HitTest(Point pt)
+                    {
+                        return this.Visible && ClientRectangle.Contains(PointToClient(pt)) ? DockStyle : DockStyle.None;
+                    }
+                }
+                #endregion PanelIndicator
+
+                #region PaneIndicator
+                private class PaneIndicator : PictureBox, IHitTest
+                {
+                    private struct HotSpotIndex
+                    {
+                        public HotSpotIndex(int x, int y, DockStyle dockStyle)
+                        {
+                            m_x = x;
+                            m_y = y;
+                            m_dockStyle = dockStyle;
+                        }
+
+                        private int m_x;
+                        public int X
+                        {
+                            get { return m_x; }
+                        }
+
+                        private int m_y;
+                        public int Y
+                        {
+                            get { return m_y; }
+                        }
+
+                        private DockStyle m_dockStyle;
+                        public DockStyle DockStyle
+                        {
+                            get { return m_dockStyle; }
+                        }
+                    }
+
+                    private static Bitmap _bitmapPaneDiamond = Resources.DockIndicator_PaneDiamond;
+                    private static Bitmap _bitmapPaneDiamondLeft = Resources.DockIndicator_PaneDiamond_Left;
+                    private static Bitmap _bitmapPaneDiamondRight = Resources.DockIndicator_PaneDiamond_Right;
+                    private static Bitmap _bitmapPaneDiamondTop = Resources.DockIndicator_PaneDiamond_Top;
+                    private static Bitmap _bitmapPaneDiamondBottom = Resources.DockIndicator_PaneDiamond_Bottom;
+                    private static Bitmap _bitmapPaneDiamondFill = Resources.DockIndicator_PaneDiamond_Fill;
+                    private static Bitmap _bitmapPaneDiamondHotSpot = Resources.DockIndicator_PaneDiamond_HotSpot;
+                    private static Bitmap _bitmapPaneDiamondHotSpotIndex = Resources.DockIndicator_PaneDiamond_HotSpotIndex;
+                    private static HotSpotIndex[] _hotSpots = new HotSpotIndex[]
+			{
+				new HotSpotIndex(1, 0, DockStyle.Top),
+				new HotSpotIndex(0, 1, DockStyle.Left),
+				new HotSpotIndex(1, 1, DockStyle.Fill),
+				new HotSpotIndex(2, 1, DockStyle.Right),
+				new HotSpotIndex(1, 2, DockStyle.Bottom)
+			};
+                    private static GraphicsPath _displayingGraphicsPath = DrawHelper.CalculateGraphicsPathFromBitmap(_bitmapPaneDiamond);
+
+                    public PaneIndicator()
+                    {
+                        SizeMode = PictureBoxSizeMode.AutoSize;
+                        Image = _bitmapPaneDiamond;
+                        Region = new Region(DisplayingGraphicsPath);
+                    }
+
+                    public static GraphicsPath DisplayingGraphicsPath
+                    {
+                        get { return _displayingGraphicsPath; }
+                    }
+
+                    public DockStyle HitTest(Point pt)
+                    {
+                        if (!Visible)
+                            return DockStyle.None;
+
+                        pt = PointToClient(pt);
+                        if (!ClientRectangle.Contains(pt))
+                            return DockStyle.None;
+
+                        for (int i = _hotSpots.GetLowerBound(0); i <= _hotSpots.GetUpperBound(0); i++)
+                        {
+                            if (_bitmapPaneDiamondHotSpot.GetPixel(pt.X, pt.Y) == _bitmapPaneDiamondHotSpotIndex.GetPixel(_hotSpots[i].X, _hotSpots[i].Y))
+                                return _hotSpots[i].DockStyle;
+                        }
+
+                        return DockStyle.None;
+                    }
+
+                    private DockStyle m_status = DockStyle.None;
+                    public DockStyle Status
+                    {
+                        get { return m_status; }
+                        set
+                        {
+                            m_status = value;
+                            if (m_status == DockStyle.None)
+                                Image = _bitmapPaneDiamond;
+                            else if (m_status == DockStyle.Left)
+                                Image = _bitmapPaneDiamondLeft;
+                            else if (m_status == DockStyle.Right)
+                                Image = _bitmapPaneDiamondRight;
+                            else if (m_status == DockStyle.Top)
+                                Image = _bitmapPaneDiamondTop;
+                            else if (m_status == DockStyle.Bottom)
+                                Image = _bitmapPaneDiamondBottom;
+                            else if (m_status == DockStyle.Fill)
+                                Image = _bitmapPaneDiamondFill;
+                        }
+                    }
+                }
+                #endregion PaneIndicator
+
+                #region consts
+                private int _PanelIndicatorMargin = 10;
+                #endregion
+
+                private DockDragHandler m_dragHandler;
+
+                public DockIndicator(DockDragHandler dragHandler)
+                {
+                    m_dragHandler = dragHandler;
+                    Controls.AddRange(new Control[] {
+			            PaneDiamond,
+			            PanelLeft,
+			            PanelRight,
+			            PanelTop,
+			            PanelBottom,
+			            PanelFill
+			            });
+                    Region = new Region(Rectangle.Empty);
+                }
+
+                private PaneIndicator m_paneDiamond = null;
+                private PaneIndicator PaneDiamond
+                {
+                    get
+                    {
+                        if (m_paneDiamond == null)
+                            m_paneDiamond = new PaneIndicator();
+
+                        return m_paneDiamond;
+                    }
+                }
+
+                private PanelIndicator m_panelLeft = null;
+                private PanelIndicator PanelLeft
+                {
+                    get
+                    {
+                        if (m_panelLeft == null)
+                            m_panelLeft = new PanelIndicator(DockStyle.Left);
+
+                        return m_panelLeft;
+                    }
+                }
+
+                private PanelIndicator m_panelRight = null;
+                private PanelIndicator PanelRight
+                {
+                    get
+                    {
+                        if (m_panelRight == null)
+                            m_panelRight = new PanelIndicator(DockStyle.Right);
+
+                        return m_panelRight;
+                    }
+                }
+
+                private PanelIndicator m_panelTop = null;
+                private PanelIndicator PanelTop
+                {
+                    get
+                    {
+                        if (m_panelTop == null)
+                            m_panelTop = new PanelIndicator(DockStyle.Top);
+
+                        return m_panelTop;
+                    }
+                }
+
+                private PanelIndicator m_panelBottom = null;
+                private PanelIndicator PanelBottom
+                {
+                    get
+                    {
+                        if (m_panelBottom == null)
+                            m_panelBottom = new PanelIndicator(DockStyle.Bottom);
+
+                        return m_panelBottom;
+                    }
+                }
+
+                private PanelIndicator m_panelFill = null;
+                private PanelIndicator PanelFill
+                {
+                    get
+                    {
+                        if (m_panelFill == null)
+                            m_panelFill = new PanelIndicator(DockStyle.Fill);
+
+                        return m_panelFill;
+                    }
+                }
+
+                private bool m_fullPanelEdge = false;
+                public bool FullPanelEdge
+                {
+                    get { return m_fullPanelEdge; }
+                    set
+                    {
+                        if (m_fullPanelEdge == value)
+                            return;
+
+                        m_fullPanelEdge = value;
+                        RefreshChanges();
+                    }
+                }
+
+                public DockDragHandler DragHandler
+                {
+                    get { return m_dragHandler; }
+                }
+
+                public DockPanel DockPanel
+                {
+                    get { return DragHandler.DockPanel; }
+                }
+
+                private DockPane m_dockPane = null;
+                public DockPane DockPane
+                {
+                    get { return m_dockPane; }
+                    internal set
+                    {
+                        if (m_dockPane == value)
+                            return;
+
+                        DockPane oldDisplayingPane = DisplayingPane;
+                        m_dockPane = value;
+                        if (oldDisplayingPane != DisplayingPane)
+                            RefreshChanges();
+                    }
+                }
+
+                private IHitTest m_hitTest = null;
+                private IHitTest HitTestResult
+                {
+                    get { return m_hitTest; }
+                    set
+                    {
+                        if (m_hitTest == value)
+                            return;
+
+                        if (m_hitTest != null)
+                            m_hitTest.Status = DockStyle.None;
+
+                        m_hitTest = value;
+                    }
+                }
+
+                private DockPane DisplayingPane
+                {
+                    get { return ShouldPaneDiamondVisible() ? DockPane : null; }
+                }
+
+                private void RefreshChanges()
+                {
+                    Region region = new Region(Rectangle.Empty);
+                    Rectangle rectDockArea = FullPanelEdge ? DockPanel.DockArea : DockPanel.DocumentWindowBounds;
+
+                    rectDockArea = RectangleToClient(DockPanel.RectangleToScreen(rectDockArea));
+                    if (ShouldPanelIndicatorVisible(DockState.DockLeft))
+                    {
+                        PanelLeft.Location = new Point(rectDockArea.X + _PanelIndicatorMargin, rectDockArea.Y + (rectDockArea.Height - PanelRight.Height) / 2);
+                        PanelLeft.Visible = true;
+                        region.Union(PanelLeft.Bounds);
+                    }
+                    else
+                        PanelLeft.Visible = false;
+
+                    if (ShouldPanelIndicatorVisible(DockState.DockRight))
+                    {
+                        PanelRight.Location = new Point(rectDockArea.X + rectDockArea.Width - PanelRight.Width - _PanelIndicatorMargin, rectDockArea.Y + (rectDockArea.Height - PanelRight.Height) / 2);
+                        PanelRight.Visible = true;
+                        region.Union(PanelRight.Bounds);
+                    }
+                    else
+                        PanelRight.Visible = false;
+
+                    if (ShouldPanelIndicatorVisible(DockState.DockTop))
+                    {
+                        PanelTop.Location = new Point(rectDockArea.X + (rectDockArea.Width - PanelTop.Width) / 2, rectDockArea.Y + _PanelIndicatorMargin);
+                        PanelTop.Visible = true;
+                        region.Union(PanelTop.Bounds);
+                    }
+                    else
+                        PanelTop.Visible = false;
+
+                    if (ShouldPanelIndicatorVisible(DockState.DockBottom))
+                    {
+                        PanelBottom.Location = new Point(rectDockArea.X + (rectDockArea.Width - PanelBottom.Width) / 2, rectDockArea.Y + rectDockArea.Height - PanelBottom.Height - _PanelIndicatorMargin);
+                        PanelBottom.Visible = true;
+                        region.Union(PanelBottom.Bounds);
+                    }
+                    else
+                        PanelBottom.Visible = false;
+
+                    if (ShouldPanelIndicatorVisible(DockState.Document))
+                    {
+                        Rectangle rectDocumentWindow = RectangleToClient(DockPanel.RectangleToScreen(DockPanel.DocumentWindowBounds));
+                        PanelFill.Location = new Point(rectDocumentWindow.X + (rectDocumentWindow.Width - PanelFill.Width) / 2, rectDocumentWindow.Y + (rectDocumentWindow.Height - PanelFill.Height) / 2);
+                        PanelFill.Visible = true;
+                        region.Union(PanelFill.Bounds);
+                    }
+                    else
+                        PanelFill.Visible = false;
+
+                    if (ShouldPaneDiamondVisible())
+                    {
+                        Rectangle rect = RectangleToClient(DockPane.RectangleToScreen(DockPane.ClientRectangle));
+                        PaneDiamond.Location = new Point(rect.Left + (rect.Width - PaneDiamond.Width) / 2, rect.Top + (rect.Height - PaneDiamond.Height) / 2);
+                        PaneDiamond.Visible = true;
+                        using (GraphicsPath graphicsPath = PaneIndicator.DisplayingGraphicsPath.Clone() as GraphicsPath)
+                        {
+                            Point[] pts = new Point[]
+						{
+							new Point(PaneDiamond.Left, PaneDiamond.Top),
+							new Point(PaneDiamond.Right, PaneDiamond.Top),
+							new Point(PaneDiamond.Left, PaneDiamond.Bottom)
+						};
+                            using (Matrix matrix = new Matrix(PaneDiamond.ClientRectangle, pts))
+                            {
+                                graphicsPath.Transform(matrix);
+                            }
+                            region.Union(graphicsPath);
+                        }
+                    }
+                    else
+                        PaneDiamond.Visible = false;
+
+                    Region = region;
+                }
+
+                private bool ShouldPanelIndicatorVisible(DockState dockState)
+                {
+                    if (!Visible)
+                        return false;
+
+                    if (DockPanel.DockWindows[dockState].Visible)
+                        return false;
+
+                    return DragHandler.DragSource.IsDockStateValid(dockState);
+                }
+
+                private bool ShouldPaneDiamondVisible()
+                {
+                    if (DockPane == null)
+                        return false;
+
+                    if (!DockPanel.AllowEndUserNestedDocking)
+                        return false;
+
+                    return DragHandler.DragSource.CanDockTo(DockPane);
+                }
+
+                public override void Show(bool bActivate)
+                {
+                    base.Show(bActivate);
+                    Bounds = SystemInformation.VirtualScreen;
+                    RefreshChanges();
+                }
+
+                public void TestDrop()
+                {
+                    Point pt = Control.MousePosition;
+                    DockPane = DockHelper.PaneAtPoint(pt, DockPanel);
+
+                    if (TestDrop(PanelLeft, pt) != DockStyle.None)
+                        HitTestResult = PanelLeft;
+                    else if (TestDrop(PanelRight, pt) != DockStyle.None)
+                        HitTestResult = PanelRight;
+                    else if (TestDrop(PanelTop, pt) != DockStyle.None)
+                        HitTestResult = PanelTop;
+                    else if (TestDrop(PanelBottom, pt) != DockStyle.None)
+                        HitTestResult = PanelBottom;
+                    else if (TestDrop(PanelFill, pt) != DockStyle.None)
+                        HitTestResult = PanelFill;
+                    else if (TestDrop(PaneDiamond, pt) != DockStyle.None)
+                        HitTestResult = PaneDiamond;
+                    else
+                        HitTestResult = null;
+
+                    if (HitTestResult != null)
+                    {
+                        if (HitTestResult is PaneIndicator)
+                            DragHandler.Outline.Show(DockPane, HitTestResult.Status);
+                        else
+                            DragHandler.Outline.Show(DockPanel, HitTestResult.Status, FullPanelEdge);
+                    }
+                }
+
+                private static DockStyle TestDrop(IHitTest hitTest, Point pt)
+                {
+                    return hitTest.Status = hitTest.HitTest(pt);
+                }
+            }
+
+            private class DockOutline : DockOutlineBase
+            {
+                public DockOutline()
+                {
+                    m_dragForm = new DragForm();
+                    SetDragForm(Rectangle.Empty);
+                    DragForm.BackColor = SystemColors.ActiveCaption;
+                    DragForm.Opacity = 0.5;
+                    DragForm.Show(false);
+                }
+
+                DragForm m_dragForm;
+                private DragForm DragForm
+                {
+                    get { return m_dragForm; }
+                }
+
+                protected override void OnShow()
+                {
+                    CalculateRegion();
+                }
+
+                protected override void OnClose()
+                {
+                    DragForm.Close();
+                }
+
+                private void CalculateRegion()
+                {
+                    if (SameAsOldValue)
+                        return;
+
+                    if (!FloatWindowBounds.IsEmpty)
+                        SetOutline(FloatWindowBounds);
+                    else if (DockTo is DockPanel)
+                        SetOutline(DockTo as DockPanel, Dock, (ContentIndex != 0));
+                    else if (DockTo is DockPane)
+                        SetOutline(DockTo as DockPane, Dock, ContentIndex);
+                    else
+                        SetOutline();
+                }
+
+                private void SetOutline()
+                {
+                    SetDragForm(Rectangle.Empty);
+                }
+
+                private void SetOutline(Rectangle floatWindowBounds)
+                {
+                    SetDragForm(floatWindowBounds);
+                }
+
+                private void SetOutline(DockPanel dockPanel, DockStyle dock, bool fullPanelEdge)
+                {
+                    Rectangle rect = fullPanelEdge ? dockPanel.DockArea : dockPanel.DocumentWindowBounds;
+                    rect.Location = dockPanel.PointToScreen(rect.Location);
+                    if (dock == DockStyle.Top)
+                    {
+                        int height = dockPanel.GetDockWindowSize(DockState.DockTop);
+                        rect = new Rectangle(rect.X, rect.Y, rect.Width, height);
+                    }
+                    else if (dock == DockStyle.Bottom)
+                    {
+                        int height = dockPanel.GetDockWindowSize(DockState.DockBottom);
+                        rect = new Rectangle(rect.X, rect.Bottom - height, rect.Width, height);
+                    }
+                    else if (dock == DockStyle.Left)
+                    {
+                        int width = dockPanel.GetDockWindowSize(DockState.DockLeft);
+                        rect = new Rectangle(rect.X, rect.Y, width, rect.Height);
+                    }
+                    else if (dock == DockStyle.Right)
+                    {
+                        int width = dockPanel.GetDockWindowSize(DockState.DockRight);
+                        rect = new Rectangle(rect.Right - width, rect.Y, width, rect.Height);
+                    }
+                    else if (dock == DockStyle.Fill)
+                    {
+                        rect = dockPanel.DocumentWindowBounds;
+                        rect.Location = dockPanel.PointToScreen(rect.Location);
+                    }
+
+                    SetDragForm(rect);
+                }
+
+                private void SetOutline(DockPane pane, DockStyle dock, int contentIndex)
+                {
+                    if (dock != DockStyle.Fill)
+                    {
+                        Rectangle rect = pane.DisplayingRectangle;
+                        if (dock == DockStyle.Right)
+                            rect.X += rect.Width / 2;
+                        if (dock == DockStyle.Bottom)
+                            rect.Y += rect.Height / 2;
+                        if (dock == DockStyle.Left || dock == DockStyle.Right)
+                            rect.Width -= rect.Width / 2;
+                        if (dock == DockStyle.Top || dock == DockStyle.Bottom)
+                            rect.Height -= rect.Height / 2;
+                        rect.Location = pane.PointToScreen(rect.Location);
+
+                        SetDragForm(rect);
+                    }
+                    else if (contentIndex == -1)
+                    {
+                        Rectangle rect = pane.DisplayingRectangle;
+                        rect.Location = pane.PointToScreen(rect.Location);
+                        SetDragForm(rect);
+                    }
+                    else
+                    {
+                        using (GraphicsPath path = pane.TabStripControl.GetOutline(contentIndex))
+                        {
+                            RectangleF rectF = path.GetBounds();
+                            Rectangle rect = new Rectangle((int)rectF.X, (int)rectF.Y, (int)rectF.Width, (int)rectF.Height);
+                            using (Matrix matrix = new Matrix(rect, new Point[] { new Point(0, 0), new Point(rect.Width, 0), new Point(0, rect.Height) }))
+                            {
+                                path.Transform(matrix);
+                            }
+                            Region region = new Region(path);
+                            SetDragForm(rect, region);
+                        }
+                    }
+                }
+
+                private void SetDragForm(Rectangle rect)
+                {
+                    DragForm.Bounds = rect;
+                    if (rect == Rectangle.Empty)
+                        DragForm.Region = new Region(Rectangle.Empty);
+                    else if (DragForm.Region != null)
+                        DragForm.Region = null;
+                }
+
+                private void SetDragForm(Rectangle rect, Region region)
+                {
+                    DragForm.Bounds = rect;
+                    DragForm.Region = region;
+                }
+            }
+
+            public DockDragHandler(DockPanel panel)
+                : base(panel)
+            {
+            }
+
+            public new IDockDragSource DragSource
+            {
+                get { return base.DragSource as IDockDragSource; }
+                set { base.DragSource = value; }
+            }
+
+            private DockOutlineBase m_outline;
+            public DockOutlineBase Outline
+            {
+                get { return m_outline; }
+                private set { m_outline = value; }
+            }
+
+            private DockIndicator m_indicator;
+            private DockIndicator Indicator
+            {
+                get { return m_indicator; }
+                set { m_indicator = value; }
+            }
+
+            private Rectangle m_floatOutlineBounds;
+            private Rectangle FloatOutlineBounds
+            {
+                get { return m_floatOutlineBounds; }
+                set { m_floatOutlineBounds = value; }
+            }
+
+            public void BeginDrag(IDockDragSource dragSource)
+            {
+                DragSource = dragSource;
+
+                if (!BeginDrag())
+                {
+                    DragSource = null;
+                    return;
+                }
+
+                Outline = new DockOutline();
+                Indicator = new DockIndicator(this);
+                Indicator.Show(false);
+
+                FloatOutlineBounds = DragSource.BeginDrag(StartMousePosition);
+            }
+
+            protected override void OnDragging()
+            {
+                TestDrop();
+            }
+
+            protected override void OnEndDrag(bool abort)
+            {
+                DockPanel.SuspendLayout(true);
+
+                Outline.Close();
+                Indicator.Close();
+
+                EndDrag(abort);
+
+                // Queue a request to layout all children controls
+                DockPanel.PerformMdiClientLayout();
+
+                DockPanel.ResumeLayout(true, true);
+
+                DragSource = null;
+            }
+
+            private void TestDrop()
+            {
+                Outline.FlagTestDrop = false;
+
+                Indicator.FullPanelEdge = ((Control.ModifierKeys & Keys.Shift) != 0);
+
+                if ((Control.ModifierKeys & Keys.Control) == 0)
+                {
+                    Indicator.TestDrop();
+
+                    if (!Outline.FlagTestDrop)
+                    {
+                        DockPane pane = DockHelper.PaneAtPoint(Control.MousePosition, DockPanel);
+                        if (pane != null && DragSource.IsDockStateValid(pane.DockState))
+                            pane.TestDrop(DragSource, Outline);
+                    }
+
+                    if (!Outline.FlagTestDrop && DragSource.IsDockStateValid(DockState.Float))
+                    {
+                        FloatWindow floatWindow = DockHelper.FloatWindowAtPoint(Control.MousePosition, DockPanel);
+                        if (floatWindow != null)
+                            floatWindow.TestDrop(DragSource, Outline);
+                    }
+                }
+                else
+                    Indicator.DockPane = DockHelper.PaneAtPoint(Control.MousePosition, DockPanel);
+
+                if (!Outline.FlagTestDrop)
+                {
+                    if (DragSource.IsDockStateValid(DockState.Float))
+                    {
+                        Rectangle rect = FloatOutlineBounds;
+                        rect.Offset(Control.MousePosition.X - StartMousePosition.X, Control.MousePosition.Y - StartMousePosition.Y);
+                        Outline.Show(rect);
+                    }
+                }
+
+                if (!Outline.FlagTestDrop)
+                {
+                    Cursor.Current = Cursors.No;
+                    Outline.Show();
+                }
+                else
+                    Cursor.Current = DragControl.Cursor;
+            }
+
+            private void EndDrag(bool abort)
+            {
+                if (abort)
+                    return;
+
+                if (!Outline.FloatWindowBounds.IsEmpty)
+                    DragSource.FloatAt(Outline.FloatWindowBounds);
+                else if (Outline.DockTo is DockPane)
+                {
+                    DockPane pane = Outline.DockTo as DockPane;
+                    DragSource.DockTo(pane, Outline.Dock, Outline.ContentIndex);
+                }
+                else if (Outline.DockTo is DockPanel)
+                {
+                    DockPanel panel = Outline.DockTo as DockPanel;
+                    panel.UpdateDockWindowZOrder(Outline.Dock, Outline.FlagFullEdge);
+                    DragSource.DockTo(panel, Outline.Dock);
+                }
+            }
+        }
+
+        private DockDragHandler m_dockDragHandler = null;
+        private DockDragHandler GetDockDragHandler()
+        {
+            if (m_dockDragHandler == null)
+                m_dockDragHandler = new DockDragHandler(this);
+            return m_dockDragHandler;
+        }
+
+        internal void BeginDrag(IDockDragSource dragSource)
+        {
+            GetDockDragHandler().BeginDrag(dragSource);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.DragHandler.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.DragHandler.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.DragHandler.cs	(revision 2645)
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPanel
+    {
+        /// <summary>
+        /// DragHandlerBase is the base class for drag handlers. The derived class should:
+        ///   1. Define its public method BeginDrag. From within this public BeginDrag method,
+        ///      DragHandlerBase.BeginDrag should be called to initialize the mouse capture
+        ///      and message filtering.
+        ///   2. Override the OnDragging and OnEndDrag methods.
+        /// </summary>
+        private abstract class DragHandlerBase : NativeWindow, IMessageFilter
+        {
+            protected DragHandlerBase()
+            {
+            }
+
+            protected abstract Control DragControl
+            {
+                get;
+            }
+
+            private Point m_startMousePosition = Point.Empty;
+            protected Point StartMousePosition
+            {
+                get { return m_startMousePosition; }
+                private set { m_startMousePosition = value; }
+            }
+
+            protected bool BeginDrag()
+            {
+                // Avoid re-entrance;
+                lock (this)
+                {
+                    if (DragControl == null)
+                        return false;
+
+                    StartMousePosition = Control.MousePosition;
+
+                    if (!NativeMethods.DragDetect(DragControl.Handle, StartMousePosition))
+                        return false;
+
+                    DragControl.FindForm().Capture = true;
+                    AssignHandle(DragControl.FindForm().Handle);
+                    Application.AddMessageFilter(this);
+                    return true;
+                }
+            }
+
+            protected abstract void OnDragging();
+
+            protected abstract void OnEndDrag(bool abort);
+
+            private void EndDrag(bool abort)
+            {
+                ReleaseHandle();
+                Application.RemoveMessageFilter(this);
+                DragControl.FindForm().Capture = false;
+
+                OnEndDrag(abort);
+            }
+
+            bool IMessageFilter.PreFilterMessage(ref Message m)
+            {
+                if (m.Msg == (int)Win32.Msgs.WM_MOUSEMOVE)
+                    OnDragging();
+                else if (m.Msg == (int)Win32.Msgs.WM_LBUTTONUP)
+                    EndDrag(false);
+                else if (m.Msg == (int)Win32.Msgs.WM_CAPTURECHANGED)
+                    EndDrag(true);
+                else if (m.Msg == (int)Win32.Msgs.WM_KEYDOWN && (int)m.WParam == (int)Keys.Escape)
+                    EndDrag(true);
+
+                return OnPreFilterMessage(ref m);
+            }
+
+            protected virtual bool OnPreFilterMessage(ref Message m)
+            {
+                return false;
+            }
+
+            protected sealed override void WndProc(ref Message m)
+            {
+                if (m.Msg == (int)Win32.Msgs.WM_CANCELMODE || m.Msg == (int)Win32.Msgs.WM_CAPTURECHANGED)
+                    EndDrag(true);
+
+                base.WndProc(ref m);
+            }
+        }
+
+        private abstract class DragHandler : DragHandlerBase
+        {
+            private DockPanel m_dockPanel;
+
+            protected DragHandler(DockPanel dockPanel)
+            {
+                m_dockPanel = dockPanel;
+            }
+
+            public DockPanel DockPanel
+            {
+                get { return m_dockPanel; }
+            }
+
+            private IDragSource m_dragSource;
+            protected IDragSource DragSource
+            {
+                get { return m_dragSource; }
+                set { m_dragSource = value; }
+            }
+
+            protected sealed override Control DragControl
+            {
+                get { return DragSource == null ? null : DragSource.DragControl; }
+            }
+
+            protected sealed override bool OnPreFilterMessage(ref Message m)
+            {
+                if ((m.Msg == (int)Win32.Msgs.WM_KEYDOWN || m.Msg == (int)Win32.Msgs.WM_KEYUP) &&
+                    ((int)m.WParam == (int)Keys.ControlKey || (int)m.WParam == (int)Keys.ShiftKey))
+                    OnDragging();
+
+                return base.OnPreFilterMessage(ref m);
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.FocusManager.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.FocusManager.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.FocusManager.cs	(revision 2645)
@@ -0,0 +1,568 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    internal interface IContentFocusManager
+    {
+        void Activate(IDockContent content);
+        void GiveUpFocus(IDockContent content);
+        void AddToList(IDockContent content);
+        void RemoveFromList(IDockContent content);
+    }
+
+    partial class DockPanel
+    {
+        private interface IFocusManager
+        {
+            void SuspendFocusTracking();
+            void ResumeFocusTracking();
+            bool IsFocusTrackingSuspended { get; }
+            IDockContent ActiveContent { get; }
+            DockPane ActivePane { get; }
+            IDockContent ActiveDocument { get; }
+            DockPane ActiveDocumentPane { get; }
+        }
+
+        private class FocusManagerImpl : Component, IContentFocusManager, IFocusManager
+        {
+            private class HookEventArgs : EventArgs
+            {
+                [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
+                public int HookCode;
+                [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
+                public IntPtr wParam;
+                public IntPtr lParam;
+            }
+
+            private class LocalWindowsHook : IDisposable
+            {
+                // Internal properties
+                private IntPtr m_hHook = IntPtr.Zero;
+                private NativeMethods.HookProc m_filterFunc = null;
+                private Win32.HookType m_hookType;
+
+                // Event delegate
+                public delegate void HookEventHandler(object sender, HookEventArgs e);
+
+                // Event: HookInvoked 
+                public event HookEventHandler HookInvoked;
+                protected void OnHookInvoked(HookEventArgs e)
+                {
+                    if (HookInvoked != null)
+                        HookInvoked(this, e);
+                }
+
+                public LocalWindowsHook(Win32.HookType hook)
+                {
+                    m_hookType = hook;
+                    m_filterFunc = new NativeMethods.HookProc(this.CoreHookProc);
+                }
+
+                // Default filter function
+                public IntPtr CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
+                {
+                    if (code < 0)
+                        return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam);
+
+                    // Let clients determine what to do
+                    HookEventArgs e = new HookEventArgs();
+                    e.HookCode = code;
+                    e.wParam = wParam;
+                    e.lParam = lParam;
+                    OnHookInvoked(e);
+
+                    // Yield to the next hook in the chain
+                    return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam);
+                }
+
+                // Install the hook
+                public void Install()
+                {
+                    if (m_hHook != IntPtr.Zero)
+                        Uninstall();
+
+                    int threadId = NativeMethods.GetCurrentThreadId();
+                    m_hHook = NativeMethods.SetWindowsHookEx(m_hookType, m_filterFunc, IntPtr.Zero, threadId);
+                }
+
+                // Uninstall the hook
+                public void Uninstall()
+                {
+                    if (m_hHook != IntPtr.Zero)
+                    {
+                        NativeMethods.UnhookWindowsHookEx(m_hHook);
+                        m_hHook = IntPtr.Zero;
+                    }
+                }
+
+                ~LocalWindowsHook()
+                {
+                    Dispose(false);
+                }
+
+                public void Dispose()
+                {
+                    Dispose(true);
+                    GC.SuppressFinalize(this);
+                }
+
+                protected virtual void Dispose(bool disposing)
+                {
+                    Uninstall();
+                }
+            }
+
+            private LocalWindowsHook m_localWindowsHook;
+            private LocalWindowsHook.HookEventHandler m_hookEventHandler;
+
+            public FocusManagerImpl(DockPanel dockPanel)
+            {
+                m_dockPanel = dockPanel;
+                m_localWindowsHook = new LocalWindowsHook(Win32.HookType.WH_CALLWNDPROCRET);
+                m_hookEventHandler = new LocalWindowsHook.HookEventHandler(HookEventHandler);
+                m_localWindowsHook.HookInvoked += m_hookEventHandler;
+                m_localWindowsHook.Install();
+            }
+
+            private DockPanel m_dockPanel;
+            public DockPanel DockPanel
+            {
+                get { return m_dockPanel; }
+            }
+
+            private bool m_disposed = false;
+            protected override void Dispose(bool disposing)
+            {
+                lock (this)
+                {
+                    if (!m_disposed && disposing)
+                    {
+                        m_localWindowsHook.Dispose();
+                        m_disposed = true;
+                    }
+
+                    base.Dispose(disposing);
+                }
+            }
+
+            private IDockContent m_contentActivating = null;
+            private IDockContent ContentActivating
+            {
+                get { return m_contentActivating; }
+                set { m_contentActivating = value; }
+            }
+
+            public void Activate(IDockContent content)
+            {
+                if (IsFocusTrackingSuspended)
+                {
+                    ContentActivating = content;
+                    return;
+                }
+
+                if (content == null)
+                    return;
+                DockContentHandler handler = content.DockHandler;
+                if (handler.Form.IsDisposed)
+                    return; // Should not reach here, but better than throwing an exception
+                if (ContentContains(content, handler.ActiveWindowHandle))
+                    NativeMethods.SetFocus(handler.ActiveWindowHandle);
+                if (!handler.Form.ContainsFocus)
+                {
+                    if (!handler.Form.SelectNextControl(handler.Form.ActiveControl, true, true, true, true))
+                        // Since DockContent Form is not selectalbe, use Win32 SetFocus instead
+                        NativeMethods.SetFocus(handler.Form.Handle);
+                }
+            }
+
+            private List<IDockContent> m_listContent = new List<IDockContent>();
+            private List<IDockContent> ListContent
+            {
+                get { return m_listContent; }
+            }
+            public void AddToList(IDockContent content)
+            {
+                if (ListContent.Contains(content) || IsInActiveList(content))
+                    return;
+
+                ListContent.Add(content);
+            }
+
+            public void RemoveFromList(IDockContent content)
+            {
+                if (IsInActiveList(content))
+                    RemoveFromActiveList(content);
+                if (ListContent.Contains(content))
+                    ListContent.Remove(content);
+            }
+
+            private IDockContent m_lastActiveContent = null;
+            private IDockContent LastActiveContent
+            {
+                get { return m_lastActiveContent; }
+                set { m_lastActiveContent = value; }
+            }
+
+            private bool IsInActiveList(IDockContent content)
+            {
+                return !(content.DockHandler.NextActive == null && LastActiveContent != content);
+            }
+
+            private void AddLastToActiveList(IDockContent content)
+            {
+                IDockContent last = LastActiveContent;
+                if (last == content)
+                    return;
+
+                DockContentHandler handler = content.DockHandler;
+
+                if (IsInActiveList(content))
+                    RemoveFromActiveList(content);
+
+                handler.PreviousActive = last;
+                handler.NextActive = null;
+                LastActiveContent = content;
+                if (last != null)
+                    last.DockHandler.NextActive = LastActiveContent;
+            }
+
+            private void RemoveFromActiveList(IDockContent content)
+            {
+                if (LastActiveContent == content)
+                    LastActiveContent = content.DockHandler.PreviousActive;
+
+                IDockContent prev = content.DockHandler.PreviousActive;
+                IDockContent next = content.DockHandler.NextActive;
+                if (prev != null)
+                    prev.DockHandler.NextActive = next;
+                if (next != null)
+                    next.DockHandler.PreviousActive = prev;
+
+                content.DockHandler.PreviousActive = null;
+                content.DockHandler.NextActive = null;
+            }
+
+            public void GiveUpFocus(IDockContent content)
+            {
+                DockContentHandler handler = content.DockHandler;
+                if (!handler.Form.ContainsFocus)
+                    return;
+
+                if (IsFocusTrackingSuspended)
+                    DockPanel.DummyControl.Focus();
+
+                if (LastActiveContent == content)
+                {
+                    IDockContent prev = handler.PreviousActive;
+                    if (prev != null)
+                        Activate(prev);
+                    else if (ListContent.Count > 0)
+                        Activate(ListContent[ListContent.Count - 1]);
+                }
+                else if (LastActiveContent != null)
+                    Activate(LastActiveContent);
+                else if (ListContent.Count > 0)
+                    Activate(ListContent[ListContent.Count - 1]);
+            }
+
+            private static bool ContentContains(IDockContent content, IntPtr hWnd)
+            {
+                Control control = Control.FromChildHandle(hWnd);
+                for (Control parent = control; parent != null; parent = parent.Parent)
+                    if (parent == content.DockHandler.Form)
+                        return true;
+
+                return false;
+            }
+
+            private int m_countSuspendFocusTracking = 0;
+            public void SuspendFocusTracking()
+            {
+                m_countSuspendFocusTracking++;
+                m_localWindowsHook.HookInvoked -= m_hookEventHandler;
+            }
+
+            public void ResumeFocusTracking()
+            {
+                if (m_countSuspendFocusTracking > 0)
+                    m_countSuspendFocusTracking--;
+
+                if (m_countSuspendFocusTracking == 0)
+                {
+                    if (ContentActivating != null)
+                    {
+                        Activate(ContentActivating);
+                        ContentActivating = null;
+                    }
+                    m_localWindowsHook.HookInvoked += m_hookEventHandler;
+                    if (!InRefreshActiveWindow)
+                        RefreshActiveWindow();
+                }
+            }
+
+            public bool IsFocusTrackingSuspended
+            {
+                get { return m_countSuspendFocusTracking != 0; }
+            }
+
+            // Windows hook event handler
+            private void HookEventHandler(object sender, HookEventArgs e)
+            {
+                Win32.Msgs msg = (Win32.Msgs)Marshal.ReadInt32(e.lParam, IntPtr.Size * 3);
+
+                if (msg == Win32.Msgs.WM_KILLFOCUS)
+                {
+                    IntPtr wParam = Marshal.ReadIntPtr(e.lParam, IntPtr.Size * 2);
+                    DockPane pane = GetPaneFromHandle(wParam);
+                    if (pane == null)
+                        RefreshActiveWindow();
+                }
+                else if (msg == Win32.Msgs.WM_SETFOCUS)
+                    RefreshActiveWindow();
+            }
+
+            private DockPane GetPaneFromHandle(IntPtr hWnd)
+            {
+                Control control = Control.FromChildHandle(hWnd);
+
+                IDockContent content = null;
+                DockPane pane = null;
+                for (; control != null; control = control.Parent)
+                {
+                    content = control as IDockContent;
+                    if (content != null)
+                        content.DockHandler.ActiveWindowHandle = hWnd;
+
+                    if (content != null && content.DockHandler.DockPanel == DockPanel)
+                        return content.DockHandler.Pane;
+
+                    pane = control as DockPane;
+                    if (pane != null && pane.DockPanel == DockPanel)
+                        break;
+                }
+
+                return pane;
+            }
+
+            private bool m_inRefreshActiveWindow = false;
+            private bool InRefreshActiveWindow
+            {
+                get { return m_inRefreshActiveWindow; }
+            }
+
+            private void RefreshActiveWindow()
+            {
+                SuspendFocusTracking();
+                m_inRefreshActiveWindow = true;
+
+                DockPane oldActivePane = ActivePane;
+                IDockContent oldActiveContent = ActiveContent;
+                IDockContent oldActiveDocument = ActiveDocument;
+
+                SetActivePane();
+                SetActiveContent();
+                SetActiveDocumentPane();
+                SetActiveDocument();
+                DockPanel.AutoHideWindow.RefreshActivePane();
+
+                ResumeFocusTracking();
+                m_inRefreshActiveWindow = false;
+
+                if (oldActiveContent != ActiveContent)
+                    DockPanel.OnActiveContentChanged(EventArgs.Empty);
+                if (oldActiveDocument != ActiveDocument)
+                    DockPanel.OnActiveDocumentChanged(EventArgs.Empty);
+                if (oldActivePane != ActivePane)
+                    DockPanel.OnActivePaneChanged(EventArgs.Empty);
+            }
+
+            private DockPane m_activePane = null;
+            public DockPane ActivePane
+            {
+                get { return m_activePane; }
+            }
+
+            private void SetActivePane()
+            {
+                DockPane value = GetPaneFromHandle(NativeMethods.GetFocus());
+                if (m_activePane == value)
+                    return;
+
+                if (m_activePane != null)
+                    m_activePane.SetIsActivated(false);
+
+                m_activePane = value;
+
+                if (m_activePane != null)
+                    m_activePane.SetIsActivated(true);
+            }
+
+            private IDockContent m_activeContent = null;
+            public IDockContent ActiveContent
+            {
+                get { return m_activeContent; }
+            }
+
+            internal void SetActiveContent()
+            {
+                IDockContent value = ActivePane == null ? null : ActivePane.ActiveContent;
+
+                if (m_activeContent == value)
+                    return;
+
+                if (m_activeContent != null)
+                    m_activeContent.DockHandler.IsActivated = false;
+
+                m_activeContent = value;
+
+                if (m_activeContent != null)
+                {
+                    m_activeContent.DockHandler.IsActivated = true;
+                    if (!DockHelper.IsDockStateAutoHide((m_activeContent.DockHandler.DockState)))
+                        AddLastToActiveList(m_activeContent);
+                }
+            }
+
+            private DockPane m_activeDocumentPane = null;
+            public DockPane ActiveDocumentPane
+            {
+                get { return m_activeDocumentPane; }
+            }
+
+            private void SetActiveDocumentPane()
+            {
+                DockPane value = null;
+
+                if (ActivePane != null && ActivePane.DockState == DockState.Document)
+                    value = ActivePane;
+
+                if (value == null && DockPanel.DockWindows != null)
+                {
+                    if (ActiveDocumentPane == null)
+                        value = DockPanel.DockWindows[DockState.Document].DefaultPane;
+                    else if (ActiveDocumentPane.DockPanel != DockPanel || ActiveDocumentPane.DockState != DockState.Document)
+                        value = DockPanel.DockWindows[DockState.Document].DefaultPane;
+                    else
+                        value = ActiveDocumentPane;
+                }
+
+                if (m_activeDocumentPane == value)
+                    return;
+
+                if (m_activeDocumentPane != null)
+                    m_activeDocumentPane.SetIsActiveDocumentPane(false);
+
+                m_activeDocumentPane = value;
+
+                if (m_activeDocumentPane != null)
+                    m_activeDocumentPane.SetIsActiveDocumentPane(true);
+            }
+
+            private IDockContent m_activeDocument = null;
+            public IDockContent ActiveDocument
+            {
+                get { return m_activeDocument; }
+            }
+
+            private void SetActiveDocument()
+            {
+                IDockContent value = ActiveDocumentPane == null ? null : ActiveDocumentPane.ActiveContent;
+
+                if (m_activeDocument == value)
+                    return;
+
+                m_activeDocument = value;
+            }
+        }
+
+        private IFocusManager FocusManager
+        {
+            get { return m_focusManager; }
+        }
+
+        internal IContentFocusManager ContentFocusManager
+        {
+            get { return m_focusManager; }
+        }
+
+        internal void SaveFocus()
+        {
+            DummyControl.Focus();
+        }
+
+        [Browsable(false)]
+        public IDockContent ActiveContent
+        {
+            get { return FocusManager.ActiveContent; }
+        }
+
+        [Browsable(false)]
+        public DockPane ActivePane
+        {
+            get { return FocusManager.ActivePane; }
+        }
+
+        [Browsable(false)]
+        public IDockContent ActiveDocument
+        {
+            get { return FocusManager.ActiveDocument; }
+        }
+
+        [Browsable(false)]
+        public DockPane ActiveDocumentPane
+        {
+            get { return FocusManager.ActiveDocumentPane; }
+        }
+
+        private static readonly object ActiveDocumentChangedEvent = new object();
+        [LocalizedCategory("Category_PropertyChanged")]
+        [LocalizedDescription("DockPanel_ActiveDocumentChanged_Description")]
+        public event EventHandler ActiveDocumentChanged
+        {
+            add { Events.AddHandler(ActiveDocumentChangedEvent, value); }
+            remove { Events.RemoveHandler(ActiveDocumentChangedEvent, value); }
+        }
+        protected virtual void OnActiveDocumentChanged(EventArgs e)
+        {
+            EventHandler handler = (EventHandler)Events[ActiveDocumentChangedEvent];
+            if (handler != null)
+                handler(this, e);
+        }
+
+        private static readonly object ActiveContentChangedEvent = new object();
+        [LocalizedCategory("Category_PropertyChanged")]
+        [LocalizedDescription("DockPanel_ActiveContentChanged_Description")]
+        public event EventHandler ActiveContentChanged
+        {
+            add { Events.AddHandler(ActiveContentChangedEvent, value); }
+            remove { Events.RemoveHandler(ActiveContentChangedEvent, value); }
+        }
+        protected void OnActiveContentChanged(EventArgs e)
+        {
+            EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent];
+            if (handler != null)
+                handler(this, e);
+        }
+
+        private static readonly object ActivePaneChangedEvent = new object();
+        [LocalizedCategory("Category_PropertyChanged")]
+        [LocalizedDescription("DockPanel_ActivePaneChanged_Description")]
+        public event EventHandler ActivePaneChanged
+        {
+            add { Events.AddHandler(ActivePaneChangedEvent, value); }
+            remove { Events.RemoveHandler(ActivePaneChangedEvent, value); }
+        }
+        protected virtual void OnActivePaneChanged(EventArgs e)
+        {
+            EventHandler handler = (EventHandler)Events[ActivePaneChangedEvent];
+            if (handler != null)
+                handler(this, e);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.MdiClientController.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.MdiClientController.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.MdiClientController.cs	(revision 2645)
@@ -0,0 +1,430 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Runtime.InteropServices;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPanel
+    {
+        //  This class comes from Jacob Slusser's MdiClientController class:
+        //  http://www.codeproject.com/cs/miscctrl/mdiclientcontroller.asp
+        private class MdiClientController : NativeWindow, IComponent, IDisposable
+        {
+            private bool m_autoScroll = true;
+            private BorderStyle m_borderStyle = BorderStyle.Fixed3D;
+            private MdiClient m_mdiClient = null;
+            private Form m_parentForm = null;
+            private ISite m_site = null;
+
+            public MdiClientController()
+            {
+            }
+
+            public void Dispose()
+            {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
+
+            protected virtual void Dispose(bool disposing)
+            {
+                if (disposing)
+                {
+                    lock (this)
+                    {
+                        if (Site != null && Site.Container != null)
+                            Site.Container.Remove(this);
+
+                        if (Disposed != null)
+                            Disposed(this, EventArgs.Empty);
+                    }
+                }
+            }
+
+            public bool AutoScroll
+            {
+                get { return m_autoScroll; }
+                set
+                {
+                    // By default the MdiClient control scrolls. It can appear though that
+                    // there are no scrollbars by turning them off when the non-client
+                    // area is calculated. I decided to expose this method following
+                    // the .NET vernacular of an AutoScroll property.
+                    m_autoScroll = value;
+                    if (MdiClient != null)
+                        UpdateStyles();
+                }
+            }
+
+            public BorderStyle BorderStyle
+            {
+                set
+                {
+                    // Error-check the enum.
+                    if (!Enum.IsDefined(typeof(BorderStyle), value))
+                        throw new InvalidEnumArgumentException();
+
+                    m_borderStyle = value;
+
+                    if (MdiClient == null)
+                        return;
+
+                    // This property can actually be visible in design-mode,
+                    // but to keep it consistent with the others,
+                    // prevent this from being show at design-time.
+                    if (Site != null && Site.DesignMode)
+                        return;
+
+                    // There is no BorderStyle property exposed by the MdiClient class,
+                    // but this can be controlled by Win32 functions. A Win32 ExStyle
+                    // of WS_EX_CLIENTEDGE is equivalent to a Fixed3D border and a
+                    // Style of WS_BORDER is equivalent to a FixedSingle border.
+
+                    // This code is inspired Jason Dori's article:
+                    // "Adding designable borders to user controls".
+                    // http://www.codeproject.com/cs/miscctrl/CsAddingBorders.asp
+
+                    // Get styles using Win32 calls
+                    int style = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE);
+                    int exStyle = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE);
+
+                    // Add or remove style flags as necessary.
+                    switch (m_borderStyle)
+                    {
+                        case BorderStyle.Fixed3D:
+                            exStyle |= (int)Win32.WindowExStyles.WS_EX_CLIENTEDGE;
+                            style &= ~((int)Win32.WindowStyles.WS_BORDER);
+                            break;
+
+                        case BorderStyle.FixedSingle:
+                            exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE);
+                            style |= (int)Win32.WindowStyles.WS_BORDER;
+                            break;
+
+                        case BorderStyle.None:
+                            style &= ~((int)Win32.WindowStyles.WS_BORDER);
+                            exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE);
+                            break;
+                    }
+
+                    // Set the styles using Win32 calls
+                    NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE, style);
+                    NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, exStyle);
+
+                    // Cause an update of the non-client area.
+                    UpdateStyles();
+                }
+            }
+
+            public MdiClient MdiClient
+            {
+                get { return m_mdiClient; }
+            }
+
+            [Browsable(false)]
+            public Form ParentForm
+            {
+                get { return m_parentForm; }
+                set
+                {
+                    // If the ParentForm has previously been set,
+                    // unwire events connected to the old parent.
+                    if (m_parentForm != null)
+                    {
+                        m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated);
+                        m_parentForm.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate);
+                    }
+
+                    m_parentForm = value;
+
+                    if (m_parentForm == null)
+                        return;
+
+                    // If the parent form has not been created yet,
+                    // wait to initialize the MDI client until it is.
+                    if (m_parentForm.IsHandleCreated)
+                    {
+                        InitializeMdiClient();
+                        RefreshProperties();
+                    }
+                    else
+                        m_parentForm.HandleCreated += new EventHandler(ParentFormHandleCreated);
+
+                    m_parentForm.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate);
+                }
+            }
+
+            public ISite Site
+            {
+                get { return m_site; }
+                set
+                {
+                    m_site = value;
+
+                    if (m_site == null)
+                        return;
+
+                    // If the component is dropped onto a form during design-time,
+                    // set the ParentForm property.
+                    IDesignerHost host = (value.GetService(typeof(IDesignerHost)) as IDesignerHost);
+                    if (host != null)
+                    {
+                        Form parent = host.RootComponent as Form;
+                        if (parent != null)
+                            ParentForm = parent;
+                    }
+                }
+            }
+
+            public void RenewMdiClient()
+            {
+                // Reinitialize the MdiClient and its properties.
+                InitializeMdiClient();
+                RefreshProperties();
+            }
+
+            public event EventHandler Disposed;
+
+            public event EventHandler HandleAssigned;
+
+            public event EventHandler MdiChildActivate;
+
+            public event LayoutEventHandler Layout;
+
+            protected virtual void OnHandleAssigned(EventArgs e)
+            {
+                // Raise the HandleAssigned event.
+                if (HandleAssigned != null)
+                    HandleAssigned(this, e);
+            }
+
+            protected virtual void OnMdiChildActivate(EventArgs e)
+            {
+                // Raise the MdiChildActivate event
+                if (MdiChildActivate != null)
+                    MdiChildActivate(this, e);
+            }
+
+            protected virtual void OnLayout(LayoutEventArgs e)
+            {
+                // Raise the Layout event
+                if (Layout != null)
+                    Layout(this, e);
+            }
+
+            public event PaintEventHandler Paint;
+
+            protected virtual void OnPaint(PaintEventArgs e)
+            {
+                // Raise the Paint event.
+                if (Paint != null)
+                    Paint(this, e);
+            }
+
+            protected override void WndProc(ref Message m)
+            {
+                switch (m.Msg)
+                {
+                    case (int)Win32.Msgs.WM_NCCALCSIZE:
+                        // If AutoScroll is set to false, hide the scrollbars when the control
+                        // calculates its non-client area.
+                        if (!AutoScroll)
+                            NativeMethods.ShowScrollBar(m.HWnd, (int)Win32.ScrollBars.SB_BOTH, 0 /*false*/);
+                        break;
+                }
+
+                base.WndProc(ref m);
+            }
+
+            private void ParentFormHandleCreated(object sender, EventArgs e)
+            {
+                // The form has been created, unwire the event, and initialize the MdiClient.
+                this.m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated);
+                InitializeMdiClient();
+                RefreshProperties();
+            }
+
+            private void ParentFormMdiChildActivate(object sender, EventArgs e)
+            {
+                OnMdiChildActivate(e);
+            }
+
+            private void MdiClientLayout(object sender, LayoutEventArgs e)
+            {
+                OnLayout(e);
+            }
+
+            private void MdiClientHandleDestroyed(object sender, EventArgs e)
+            {
+                // If the MdiClient handle has been released, drop the reference and
+                // release the handle.
+                if (m_mdiClient != null)
+                {
+                    m_mdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed);
+                    m_mdiClient = null;
+                }
+
+                ReleaseHandle();
+            }
+
+            private void InitializeMdiClient()
+            {
+                // If the mdiClient has previously been set, unwire events connected
+                // to the old MDI.
+                if (MdiClient != null)
+                {
+                    MdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed);
+                    MdiClient.Layout -= new LayoutEventHandler(MdiClientLayout);
+                }
+
+                if (ParentForm == null)
+                    return;
+
+                // Get the MdiClient from the parent form.
+                foreach (Control control in ParentForm.Controls)
+                {
+                    // If the form is an MDI container, it will contain an MdiClient control
+                    // just as it would any other control.
+
+                    m_mdiClient = control as MdiClient;
+                    if (m_mdiClient == null)
+                        continue;
+
+                    // Assign the MdiClient Handle to the NativeWindow.
+                    ReleaseHandle();
+                    AssignHandle(MdiClient.Handle);
+
+                    // Raise the HandleAssigned event.
+                    OnHandleAssigned(EventArgs.Empty);
+
+                    // Monitor the MdiClient for when its handle is destroyed.
+                    MdiClient.HandleDestroyed += new EventHandler(MdiClientHandleDestroyed);
+                    MdiClient.Layout += new LayoutEventHandler(MdiClientLayout);
+
+                    break;
+                }
+            }
+
+            private void RefreshProperties()
+            {
+                // Refresh all the properties
+                BorderStyle = m_borderStyle;
+                AutoScroll = m_autoScroll;
+            }
+
+            private void UpdateStyles()
+            {
+                // To show style changes, the non-client area must be repainted. Using the
+                // control's Invalidate method does not affect the non-client area.
+                // Instead use a Win32 call to signal the style has changed.
+                NativeMethods.SetWindowPos(MdiClient.Handle, IntPtr.Zero, 0, 0, 0, 0,
+                    Win32.FlagsSetWindowPos.SWP_NOACTIVATE |
+                    Win32.FlagsSetWindowPos.SWP_NOMOVE |
+                    Win32.FlagsSetWindowPos.SWP_NOSIZE |
+                    Win32.FlagsSetWindowPos.SWP_NOZORDER |
+                    Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER |
+                    Win32.FlagsSetWindowPos.SWP_FRAMECHANGED);
+            }
+        }
+
+        private MdiClientController m_mdiClientController = null;
+        private MdiClientController GetMdiClientController()
+        {
+            if (m_mdiClientController == null)
+            {
+                m_mdiClientController = new MdiClientController();
+                m_mdiClientController.HandleAssigned += new EventHandler(MdiClientHandleAssigned);
+                m_mdiClientController.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate);
+                m_mdiClientController.Layout += new LayoutEventHandler(MdiClient_Layout);
+            }
+
+            return m_mdiClientController;
+        }
+
+        private void ParentFormMdiChildActivate(object sender, EventArgs e)
+        {
+            if (GetMdiClientController().ParentForm == null)
+                return;
+
+            IDockContent content = GetMdiClientController().ParentForm.ActiveMdiChild as IDockContent;
+            if (content == null)
+                return;
+
+            if (content.DockHandler.DockPanel == this && content.DockHandler.Pane != null)
+                content.DockHandler.Pane.ActiveContent = content;
+        }
+
+        private bool MdiClientExists
+        {
+            get { return GetMdiClientController().MdiClient != null; }
+        }
+
+        private void SetMdiClientBounds(Rectangle bounds)
+        {
+            GetMdiClientController().MdiClient.Bounds = bounds;
+        }
+
+        private void SuspendMdiClientLayout()
+        {
+            if (GetMdiClientController().MdiClient != null)
+                GetMdiClientController().MdiClient.SuspendLayout();
+        }
+
+        private void ResumeMdiClientLayout(bool perform)
+        {
+            if (GetMdiClientController().MdiClient != null)
+                GetMdiClientController().MdiClient.ResumeLayout(perform);
+        }
+
+        private void PerformMdiClientLayout()
+        {
+            if (GetMdiClientController().MdiClient != null)
+                GetMdiClientController().MdiClient.PerformLayout();
+        }
+
+        // Called when:
+        // 1. DockPanel.DocumentStyle changed
+        // 2. DockPanel.Visible changed
+        // 3. MdiClientController.Handle assigned
+        private void SetMdiClient()
+        {
+            MdiClientController controller = GetMdiClientController();
+
+            if (this.DocumentStyle == DocumentStyle.DockingMdi)
+            {
+                controller.AutoScroll = false;
+                controller.BorderStyle = BorderStyle.None;
+                if (MdiClientExists)
+                    controller.MdiClient.Dock = DockStyle.Fill;
+            }
+            else if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow)
+            {
+                controller.AutoScroll = true;
+                controller.BorderStyle = BorderStyle.Fixed3D;
+                if (MdiClientExists)
+                    controller.MdiClient.Dock = DockStyle.Fill;
+            }
+            else if (this.DocumentStyle == DocumentStyle.SystemMdi)
+            {
+                controller.AutoScroll = true;
+                controller.BorderStyle = BorderStyle.Fixed3D;
+                if (controller.MdiClient != null)
+                {
+                    controller.MdiClient.Dock = DockStyle.None;
+                    controller.MdiClient.Bounds = SystemMdiClientBounds;
+                }
+            }
+        }
+
+        internal Rectangle RectangleToMdiClient(Rectangle rect)
+        {
+            if (MdiClientExists)
+                return GetMdiClientController().MdiClient.RectangleToClient(rect);
+            else
+                return Rectangle.Empty;
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.Persistor.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.Persistor.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.Persistor.cs	(revision 2645)
@@ -0,0 +1,781 @@
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Drawing;
+using WeifenLuo.WinFormsUI.Docking;
+using System.IO;
+using System.Text;
+using System.Xml;
+using System.Globalization;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPanel
+    {
+        private static class Persistor
+        {
+            private const string ConfigFileVersion = "1.0";
+            private static string[] CompatibleConfigFileVersions = new string[] { };
+
+            private class DummyContent : DockContent
+            {
+            }
+
+            private struct DockPanelStruct
+            {
+                private double m_dockLeftPortion;
+                public double DockLeftPortion
+                {
+                    get { return m_dockLeftPortion; }
+                    set { m_dockLeftPortion = value; }
+                }
+
+                private double m_dockRightPortion;
+                public double DockRightPortion
+                {
+                    get { return m_dockRightPortion; }
+                    set { m_dockRightPortion = value; }
+                }
+
+                private double m_dockTopPortion;
+                public double DockTopPortion
+                {
+                    get { return m_dockTopPortion; }
+                    set { m_dockTopPortion = value; }
+                }
+
+                private double m_dockBottomPortion;
+                public double DockBottomPortion
+                {
+                    get { return m_dockBottomPortion; }
+                    set { m_dockBottomPortion = value; }
+                }
+
+                private int m_indexActiveDocumentPane;
+                public int IndexActiveDocumentPane
+                {
+                    get { return m_indexActiveDocumentPane; }
+                    set { m_indexActiveDocumentPane = value; }
+                }
+
+                private int m_indexActivePane;
+                public int IndexActivePane
+                {
+                    get { return m_indexActivePane; }
+                    set { m_indexActivePane = value; }
+                }
+            }
+
+            private struct ContentStruct
+            {
+                private string m_persistString;
+                public string PersistString
+                {
+                    get { return m_persistString; }
+                    set { m_persistString = value; }
+                }
+
+                private double m_autoHidePortion;
+                public double AutoHidePortion
+                {
+                    get { return m_autoHidePortion; }
+                    set { m_autoHidePortion = value; }
+                }
+
+                private bool m_isHidden;
+                public bool IsHidden
+                {
+                    get { return m_isHidden; }
+                    set { m_isHidden = value; }
+                }
+
+                private bool m_isFloat;
+                public bool IsFloat
+                {
+                    get { return m_isFloat; }
+                    set { m_isFloat = value; }
+                }
+            }
+
+            private struct PaneStruct
+            {
+                private DockState m_dockState;
+                public DockState DockState
+                {
+                    get { return m_dockState; }
+                    set { m_dockState = value; }
+                }
+
+                private int m_indexActiveContent;
+                public int IndexActiveContent
+                {
+                    get { return m_indexActiveContent; }
+                    set { m_indexActiveContent = value; }
+                }
+
+                private int[] m_indexContents;
+                public int[] IndexContents
+                {
+                    get { return m_indexContents; }
+                    set { m_indexContents = value; }
+                }
+
+                private int m_zOrderIndex;
+                public int ZOrderIndex
+                {
+                    get { return m_zOrderIndex; }
+                    set { m_zOrderIndex = value; }
+                }
+            }
+
+            private struct NestedPane
+            {
+                private int m_indexPane;
+                public int IndexPane
+                {
+                    get { return m_indexPane; }
+                    set { m_indexPane = value; }
+                }
+
+                private int m_indexPrevPane;
+                public int IndexPrevPane
+                {
+                    get { return m_indexPrevPane; }
+                    set { m_indexPrevPane = value; }
+                }
+
+                private DockAlignment m_alignment;
+                public DockAlignment Alignment
+                {
+                    get { return m_alignment; }
+                    set { m_alignment = value; }
+                }
+
+                private double m_proportion;
+                public double Proportion
+                {
+                    get { return m_proportion; }
+                    set { m_proportion = value; }
+                }
+            }
+
+            private struct DockWindowStruct
+            {
+                private DockState m_dockState;
+                public DockState DockState
+                {
+                    get { return m_dockState; }
+                    set { m_dockState = value; }
+                }
+
+                private int m_zOrderIndex;
+                public int ZOrderIndex
+                {
+                    get { return m_zOrderIndex; }
+                    set { m_zOrderIndex = value; }
+                }
+
+                private NestedPane[] m_nestedPanes;
+                public NestedPane[] NestedPanes
+                {
+                    get { return m_nestedPanes; }
+                    set { m_nestedPanes = value; }
+                }
+            }
+
+            private struct FloatWindowStruct
+            {
+                private Rectangle m_bounds;
+                public Rectangle Bounds
+                {
+                    get { return m_bounds; }
+                    set { m_bounds = value; }
+                }
+
+                private int m_zOrderIndex;
+                public int ZOrderIndex
+                {
+                    get { return m_zOrderIndex; }
+                    set { m_zOrderIndex = value; }
+                }
+
+                private NestedPane[] m_nestedPanes;
+                public NestedPane[] NestedPanes
+                {
+                    get { return m_nestedPanes; }
+                    set { m_nestedPanes = value; }
+                }
+            }
+
+            public static void SaveAsXml(DockPanel dockPanel, string fileName)
+            {
+                SaveAsXml(dockPanel, fileName, Encoding.Unicode);
+            }
+
+            public static void SaveAsXml(DockPanel dockPanel, string fileName, Encoding encoding)
+            {
+                FileStream fs = new FileStream(fileName, FileMode.Create);
+                try
+                {
+                    SaveAsXml(dockPanel, fs, encoding);
+                }
+                finally
+                {
+                    fs.Close();
+                }
+            }
+
+            public static void SaveAsXml(DockPanel dockPanel, Stream stream, Encoding encoding)
+            {
+                SaveAsXml(dockPanel, stream, encoding, false);
+            }
+
+            public static void SaveAsXml(DockPanel dockPanel, Stream stream, Encoding encoding, bool upstream)
+            {
+                XmlTextWriter xmlOut = new XmlTextWriter(stream, encoding);
+
+                // Use indenting for readability
+                xmlOut.Formatting = Formatting.Indented;
+
+                if (!upstream)
+                    xmlOut.WriteStartDocument();
+
+                // Always begin file with identification and warning
+                xmlOut.WriteComment(Strings.DockPanel_Persistor_XmlFileComment1);
+                xmlOut.WriteComment(Strings.DockPanel_Persistor_XmlFileComment2);
+
+                // Associate a version number with the root element so that future version of the code
+                // will be able to be backwards compatible or at least recognise out of date versions
+                xmlOut.WriteStartElement("DockPanel");
+                xmlOut.WriteAttributeString("FormatVersion", ConfigFileVersion);
+                xmlOut.WriteAttributeString("DockLeftPortion", dockPanel.DockLeftPortion.ToString(CultureInfo.InvariantCulture));
+                xmlOut.WriteAttributeString("DockRightPortion", dockPanel.DockRightPortion.ToString(CultureInfo.InvariantCulture));
+                xmlOut.WriteAttributeString("DockTopPortion", dockPanel.DockTopPortion.ToString(CultureInfo.InvariantCulture));
+                xmlOut.WriteAttributeString("DockBottomPortion", dockPanel.DockBottomPortion.ToString(CultureInfo.InvariantCulture));
+                xmlOut.WriteAttributeString("ActiveDocumentPane", dockPanel.Panes.IndexOf(dockPanel.ActiveDocumentPane).ToString(CultureInfo.InvariantCulture));
+                xmlOut.WriteAttributeString("ActivePane", dockPanel.Panes.IndexOf(dockPanel.ActivePane).ToString(CultureInfo.InvariantCulture));
+
+                // Contents
+                xmlOut.WriteStartElement("Contents");
+                xmlOut.WriteAttributeString("Count", dockPanel.Contents.Count.ToString(CultureInfo.InvariantCulture));
+                foreach (IDockContent content in dockPanel.Contents)
+                {
+                    xmlOut.WriteStartElement("Content");
+                    xmlOut.WriteAttributeString("ID", dockPanel.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteAttributeString("PersistString", content.DockHandler.PersistString);
+                    xmlOut.WriteAttributeString("AutoHidePortion", content.DockHandler.AutoHidePortion.ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteAttributeString("IsHidden", content.DockHandler.IsHidden.ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteAttributeString("IsFloat", content.DockHandler.IsFloat.ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteEndElement();
+                }
+                xmlOut.WriteEndElement();
+
+                // Panes
+                xmlOut.WriteStartElement("Panes");
+                xmlOut.WriteAttributeString("Count", dockPanel.Panes.Count.ToString(CultureInfo.InvariantCulture));
+                foreach (DockPane pane in dockPanel.Panes)
+                {
+                    xmlOut.WriteStartElement("Pane");
+                    xmlOut.WriteAttributeString("ID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteAttributeString("DockState", pane.DockState.ToString());
+                    xmlOut.WriteAttributeString("ActiveContent", dockPanel.Contents.IndexOf(pane.ActiveContent).ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteStartElement("Contents");
+                    xmlOut.WriteAttributeString("Count", pane.Contents.Count.ToString(CultureInfo.InvariantCulture));
+                    foreach (IDockContent content in pane.Contents)
+                    {
+                        xmlOut.WriteStartElement("Content");
+                        xmlOut.WriteAttributeString("ID", pane.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteAttributeString("RefID", dockPanel.Contents.IndexOf(content).ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteEndElement();
+                    }
+                    xmlOut.WriteEndElement();
+                    xmlOut.WriteEndElement();
+                }
+                xmlOut.WriteEndElement();
+
+                // DockWindows
+                xmlOut.WriteStartElement("DockWindows");
+                int dockWindowId = 0;
+                foreach (DockWindow dw in dockPanel.DockWindows)
+                {
+                    xmlOut.WriteStartElement("DockWindow");
+                    xmlOut.WriteAttributeString("ID", dockWindowId.ToString(CultureInfo.InvariantCulture));
+                    dockWindowId++;
+                    xmlOut.WriteAttributeString("DockState", dw.DockState.ToString());
+                    xmlOut.WriteAttributeString("ZOrderIndex", dockPanel.Controls.IndexOf(dw).ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteStartElement("NestedPanes");
+                    xmlOut.WriteAttributeString("Count", dw.NestedPanes.Count.ToString(CultureInfo.InvariantCulture));
+                    foreach (DockPane pane in dw.NestedPanes)
+                    {
+                        xmlOut.WriteStartElement("Pane");
+                        xmlOut.WriteAttributeString("ID", dw.NestedPanes.IndexOf(pane).ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteAttributeString("RefID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture));
+                        NestedDockingStatus status = pane.NestedDockingStatus;
+                        xmlOut.WriteAttributeString("PrevPane", dockPanel.Panes.IndexOf(status.PreviousPane).ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteAttributeString("Alignment", status.Alignment.ToString());
+                        xmlOut.WriteAttributeString("Proportion", status.Proportion.ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteEndElement();
+                    }
+                    xmlOut.WriteEndElement();
+                    xmlOut.WriteEndElement();
+                }
+                xmlOut.WriteEndElement();
+
+                // FloatWindows
+                RectangleConverter rectConverter = new RectangleConverter();
+                xmlOut.WriteStartElement("FloatWindows");
+                xmlOut.WriteAttributeString("Count", dockPanel.FloatWindows.Count.ToString(CultureInfo.InvariantCulture));
+                foreach (FloatWindow fw in dockPanel.FloatWindows)
+                {
+                    xmlOut.WriteStartElement("FloatWindow");
+                    xmlOut.WriteAttributeString("ID", dockPanel.FloatWindows.IndexOf(fw).ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteAttributeString("Bounds", rectConverter.ConvertToInvariantString(fw.Bounds));
+                    xmlOut.WriteAttributeString("ZOrderIndex", fw.DockPanel.FloatWindows.IndexOf(fw).ToString(CultureInfo.InvariantCulture));
+                    xmlOut.WriteStartElement("NestedPanes");
+                    xmlOut.WriteAttributeString("Count", fw.NestedPanes.Count.ToString(CultureInfo.InvariantCulture));
+                    foreach (DockPane pane in fw.NestedPanes)
+                    {
+                        xmlOut.WriteStartElement("Pane");
+                        xmlOut.WriteAttributeString("ID", fw.NestedPanes.IndexOf(pane).ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteAttributeString("RefID", dockPanel.Panes.IndexOf(pane).ToString(CultureInfo.InvariantCulture));
+                        NestedDockingStatus status = pane.NestedDockingStatus;
+                        xmlOut.WriteAttributeString("PrevPane", dockPanel.Panes.IndexOf(status.PreviousPane).ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteAttributeString("Alignment", status.Alignment.ToString());
+                        xmlOut.WriteAttributeString("Proportion", status.Proportion.ToString(CultureInfo.InvariantCulture));
+                        xmlOut.WriteEndElement();
+                    }
+                    xmlOut.WriteEndElement();
+                    xmlOut.WriteEndElement();
+                }
+                xmlOut.WriteEndElement();	//	</FloatWindows>
+
+                xmlOut.WriteEndElement();
+
+                if (!upstream)
+                {
+                    xmlOut.WriteEndDocument();
+                    xmlOut.Close();
+                }
+                else
+                    xmlOut.Flush();
+            }
+
+            public static void LoadFromXml(DockPanel dockPanel, string fileName, DeserializeDockContent deserializeContent)
+            {
+                FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
+                try
+                {
+                    LoadFromXml(dockPanel, fs, deserializeContent);
+                }
+                finally
+                {
+                    fs.Close();
+                }
+            }
+
+            public static void LoadFromXml(DockPanel dockPanel, Stream stream, DeserializeDockContent deserializeContent)
+            {
+                LoadFromXml(dockPanel, stream, deserializeContent, true);
+            }
+
+            private static ContentStruct[] LoadContents(XmlTextReader xmlIn)
+            {
+                int countOfContents = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture);
+                ContentStruct[] contents = new ContentStruct[countOfContents];
+                MoveToNextElement(xmlIn);
+                for (int i = 0; i < countOfContents; i++)
+                {
+                    int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                    if (xmlIn.Name != "Content" || id != i)
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+
+                    contents[i].PersistString = xmlIn.GetAttribute("PersistString");
+                    contents[i].AutoHidePortion = Convert.ToDouble(xmlIn.GetAttribute("AutoHidePortion"), CultureInfo.InvariantCulture);
+                    contents[i].IsHidden = Convert.ToBoolean(xmlIn.GetAttribute("IsHidden"), CultureInfo.InvariantCulture);
+                    contents[i].IsFloat = Convert.ToBoolean(xmlIn.GetAttribute("IsFloat"), CultureInfo.InvariantCulture);
+                    MoveToNextElement(xmlIn);
+                }
+
+                return contents;
+            }
+
+            private static PaneStruct[] LoadPanes(XmlTextReader xmlIn)
+            {
+                EnumConverter dockStateConverter = new EnumConverter(typeof(DockState));
+                int countOfPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture);
+                PaneStruct[] panes = new PaneStruct[countOfPanes];
+                MoveToNextElement(xmlIn);
+                for (int i = 0; i < countOfPanes; i++)
+                {
+                    int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                    if (xmlIn.Name != "Pane" || id != i)
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+
+                    panes[i].DockState = (DockState)dockStateConverter.ConvertFrom(xmlIn.GetAttribute("DockState"));
+                    panes[i].IndexActiveContent = Convert.ToInt32(xmlIn.GetAttribute("ActiveContent"), CultureInfo.InvariantCulture);
+                    panes[i].ZOrderIndex = -1;
+
+                    MoveToNextElement(xmlIn);
+                    if (xmlIn.Name != "Contents")
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                    int countOfPaneContents = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture);
+                    panes[i].IndexContents = new int[countOfPaneContents];
+                    MoveToNextElement(xmlIn);
+                    for (int j = 0; j < countOfPaneContents; j++)
+                    {
+                        int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                        if (xmlIn.Name != "Content" || id2 != j)
+                            throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+
+                        panes[i].IndexContents[j] = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture);
+                        MoveToNextElement(xmlIn);
+                    }
+                }
+
+                return panes;
+            }
+
+            private static DockWindowStruct[] LoadDockWindows(XmlTextReader xmlIn, DockPanel dockPanel)
+            {
+                EnumConverter dockStateConverter = new EnumConverter(typeof(DockState));
+                EnumConverter dockAlignmentConverter = new EnumConverter(typeof(DockAlignment));
+                int countOfDockWindows = dockPanel.DockWindows.Count;
+                DockWindowStruct[] dockWindows = new DockWindowStruct[countOfDockWindows];
+                MoveToNextElement(xmlIn);
+                for (int i = 0; i < countOfDockWindows; i++)
+                {
+                    int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                    if (xmlIn.Name != "DockWindow" || id != i)
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+
+                    dockWindows[i].DockState = (DockState)dockStateConverter.ConvertFrom(xmlIn.GetAttribute("DockState"));
+                    dockWindows[i].ZOrderIndex = Convert.ToInt32(xmlIn.GetAttribute("ZOrderIndex"), CultureInfo.InvariantCulture);
+                    MoveToNextElement(xmlIn);
+                    if (xmlIn.Name != "DockList" && xmlIn.Name != "NestedPanes")
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                    int countOfNestedPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture);
+                    dockWindows[i].NestedPanes = new NestedPane[countOfNestedPanes];
+                    MoveToNextElement(xmlIn);
+                    for (int j = 0; j < countOfNestedPanes; j++)
+                    {
+                        int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                        if (xmlIn.Name != "Pane" || id2 != j)
+                            throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                        dockWindows[i].NestedPanes[j].IndexPane = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture);
+                        dockWindows[i].NestedPanes[j].IndexPrevPane = Convert.ToInt32(xmlIn.GetAttribute("PrevPane"), CultureInfo.InvariantCulture);
+                        dockWindows[i].NestedPanes[j].Alignment = (DockAlignment)dockAlignmentConverter.ConvertFrom(xmlIn.GetAttribute("Alignment"));
+                        dockWindows[i].NestedPanes[j].Proportion = Convert.ToDouble(xmlIn.GetAttribute("Proportion"), CultureInfo.InvariantCulture);
+                        MoveToNextElement(xmlIn);
+                    }
+                }
+
+                return dockWindows;
+            }
+
+            private static FloatWindowStruct[] LoadFloatWindows(XmlTextReader xmlIn)
+            {
+                EnumConverter dockAlignmentConverter = new EnumConverter(typeof(DockAlignment));
+                RectangleConverter rectConverter = new RectangleConverter();
+                int countOfFloatWindows = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture);
+                FloatWindowStruct[] floatWindows = new FloatWindowStruct[countOfFloatWindows];
+                MoveToNextElement(xmlIn);
+                for (int i = 0; i < countOfFloatWindows; i++)
+                {
+                    int id = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                    if (xmlIn.Name != "FloatWindow" || id != i)
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+
+                    floatWindows[i].Bounds = (Rectangle)rectConverter.ConvertFromInvariantString(xmlIn.GetAttribute("Bounds"));
+                    floatWindows[i].ZOrderIndex = Convert.ToInt32(xmlIn.GetAttribute("ZOrderIndex"), CultureInfo.InvariantCulture);
+                    MoveToNextElement(xmlIn);
+                    if (xmlIn.Name != "DockList" && xmlIn.Name != "NestedPanes")
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                    int countOfNestedPanes = Convert.ToInt32(xmlIn.GetAttribute("Count"), CultureInfo.InvariantCulture);
+                    floatWindows[i].NestedPanes = new NestedPane[countOfNestedPanes];
+                    MoveToNextElement(xmlIn);
+                    for (int j = 0; j < countOfNestedPanes; j++)
+                    {
+                        int id2 = Convert.ToInt32(xmlIn.GetAttribute("ID"), CultureInfo.InvariantCulture);
+                        if (xmlIn.Name != "Pane" || id2 != j)
+                            throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                        floatWindows[i].NestedPanes[j].IndexPane = Convert.ToInt32(xmlIn.GetAttribute("RefID"), CultureInfo.InvariantCulture);
+                        floatWindows[i].NestedPanes[j].IndexPrevPane = Convert.ToInt32(xmlIn.GetAttribute("PrevPane"), CultureInfo.InvariantCulture);
+                        floatWindows[i].NestedPanes[j].Alignment = (DockAlignment)dockAlignmentConverter.ConvertFrom(xmlIn.GetAttribute("Alignment"));
+                        floatWindows[i].NestedPanes[j].Proportion = Convert.ToDouble(xmlIn.GetAttribute("Proportion"), CultureInfo.InvariantCulture);
+                        MoveToNextElement(xmlIn);
+                    }
+                }
+
+                return floatWindows;
+            }
+
+            public static void LoadFromXml(DockPanel dockPanel, Stream stream, DeserializeDockContent deserializeContent, bool closeStream)
+            {
+
+                if (dockPanel.Contents.Count != 0)
+                    throw new InvalidOperationException(Strings.DockPanel_LoadFromXml_AlreadyInitialized);
+
+                XmlTextReader xmlIn = new XmlTextReader(stream);
+                xmlIn.WhitespaceHandling = WhitespaceHandling.None;
+                xmlIn.MoveToContent();
+
+                while (!xmlIn.Name.Equals("DockPanel"))
+                {
+                    if (!MoveToNextElement(xmlIn))
+                        throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                }
+
+                string formatVersion = xmlIn.GetAttribute("FormatVersion");
+                if (!IsFormatVersionValid(formatVersion))
+                    throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidFormatVersion);
+
+                DockPanelStruct dockPanelStruct = new DockPanelStruct();
+                dockPanelStruct.DockLeftPortion = Convert.ToDouble(xmlIn.GetAttribute("DockLeftPortion"), CultureInfo.InvariantCulture);
+                dockPanelStruct.DockRightPortion = Convert.ToDouble(xmlIn.GetAttribute("DockRightPortion"), CultureInfo.InvariantCulture);
+                dockPanelStruct.DockTopPortion = Convert.ToDouble(xmlIn.GetAttribute("DockTopPortion"), CultureInfo.InvariantCulture);
+                dockPanelStruct.DockBottomPortion = Convert.ToDouble(xmlIn.GetAttribute("DockBottomPortion"), CultureInfo.InvariantCulture);
+                dockPanelStruct.IndexActiveDocumentPane = Convert.ToInt32(xmlIn.GetAttribute("ActiveDocumentPane"), CultureInfo.InvariantCulture);
+                dockPanelStruct.IndexActivePane = Convert.ToInt32(xmlIn.GetAttribute("ActivePane"), CultureInfo.InvariantCulture);
+
+                // Load Contents
+                MoveToNextElement(xmlIn);
+                if (xmlIn.Name != "Contents")
+                    throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                ContentStruct[] contents = LoadContents(xmlIn);
+
+                // Load Panes
+                if (xmlIn.Name != "Panes")
+                    throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                PaneStruct[] panes = LoadPanes(xmlIn);
+
+                // Load DockWindows
+                if (xmlIn.Name != "DockWindows")
+                    throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                DockWindowStruct[] dockWindows = LoadDockWindows(xmlIn, dockPanel);
+
+                // Load FloatWindows
+                if (xmlIn.Name != "FloatWindows")
+                    throw new ArgumentException(Strings.DockPanel_LoadFromXml_InvalidXmlFormat);
+                FloatWindowStruct[] floatWindows = LoadFloatWindows(xmlIn);
+
+                if (closeStream)
+                    xmlIn.Close();
+
+                dockPanel.SuspendLayout(true);
+
+                dockPanel.DockLeftPortion = dockPanelStruct.DockLeftPortion;
+                dockPanel.DockRightPortion = dockPanelStruct.DockRightPortion;
+                dockPanel.DockTopPortion = dockPanelStruct.DockTopPortion;
+                dockPanel.DockBottomPortion = dockPanelStruct.DockBottomPortion;
+
+                // Set DockWindow ZOrders
+                int prevMaxDockWindowZOrder = int.MaxValue;
+                for (int i = 0; i < dockWindows.Length; i++)
+                {
+                    int maxDockWindowZOrder = -1;
+                    int index = -1;
+                    for (int j = 0; j < dockWindows.Length; j++)
+                    {
+                        if (dockWindows[j].ZOrderIndex > maxDockWindowZOrder && dockWindows[j].ZOrderIndex < prevMaxDockWindowZOrder)
+                        {
+                            maxDockWindowZOrder = dockWindows[j].ZOrderIndex;
+                            index = j;
+                        }
+                    }
+
+                    dockPanel.DockWindows[dockWindows[index].DockState].BringToFront();
+                    prevMaxDockWindowZOrder = maxDockWindowZOrder;
+                }
+
+                // Create Contents
+                for (int i = 0; i < contents.Length; i++)
+                {
+                    IDockContent content = deserializeContent(contents[i].PersistString);
+                    if (content == null)
+                        content = new DummyContent();
+                    content.DockHandler.DockPanel = dockPanel;
+                    content.DockHandler.AutoHidePortion = contents[i].AutoHidePortion;
+                    content.DockHandler.IsHidden = true;
+                    content.DockHandler.IsFloat = contents[i].IsFloat;
+                }
+
+                // Create panes
+                for (int i = 0; i < panes.Length; i++)
+                {
+                    DockPane pane = null;
+                    for (int j = 0; j < panes[i].IndexContents.Length; j++)
+                    {
+                        IDockContent content = dockPanel.Contents[panes[i].IndexContents[j]];
+                        if (j == 0)
+                            pane = dockPanel.DockPaneFactory.CreateDockPane(content, panes[i].DockState, false);
+                        else if (panes[i].DockState == DockState.Float)
+                            content.DockHandler.FloatPane = pane;
+                        else
+                            content.DockHandler.PanelPane = pane;
+                    }
+                }
+
+                // Assign Panes to DockWindows
+                for (int i = 0; i < dockWindows.Length; i++)
+                {
+                    for (int j = 0; j < dockWindows[i].NestedPanes.Length; j++)
+                    {
+                        DockWindow dw = dockPanel.DockWindows[dockWindows[i].DockState];
+                        int indexPane = dockWindows[i].NestedPanes[j].IndexPane;
+                        DockPane pane = dockPanel.Panes[indexPane];
+                        int indexPrevPane = dockWindows[i].NestedPanes[j].IndexPrevPane;
+                        DockPane prevPane = (indexPrevPane == -1) ? dw.NestedPanes.GetDefaultPreviousPane(pane) : dockPanel.Panes[indexPrevPane];
+                        DockAlignment alignment = dockWindows[i].NestedPanes[j].Alignment;
+                        double proportion = dockWindows[i].NestedPanes[j].Proportion;
+                        pane.DockTo(dw, prevPane, alignment, proportion);
+                        if (panes[indexPane].DockState == dw.DockState)
+                            panes[indexPane].ZOrderIndex = dockWindows[i].ZOrderIndex;
+                    }
+                }
+
+                // Create float windows
+                for (int i = 0; i < floatWindows.Length; i++)
+                {
+                    FloatWindow fw = null;
+                    for (int j = 0; j < floatWindows[i].NestedPanes.Length; j++)
+                    {
+                        int indexPane = floatWindows[i].NestedPanes[j].IndexPane;
+                        DockPane pane = dockPanel.Panes[indexPane];
+                        if (j == 0)
+                            fw = dockPanel.FloatWindowFactory.CreateFloatWindow(dockPanel, pane, floatWindows[i].Bounds);
+                        else
+                        {
+                            int indexPrevPane = floatWindows[i].NestedPanes[j].IndexPrevPane;
+                            DockPane prevPane = indexPrevPane == -1 ? null : dockPanel.Panes[indexPrevPane];
+                            DockAlignment alignment = floatWindows[i].NestedPanes[j].Alignment;
+                            double proportion = floatWindows[i].NestedPanes[j].Proportion;
+                            pane.DockTo(fw, prevPane, alignment, proportion);
+                        }
+
+                        if (panes[indexPane].DockState == fw.DockState)
+                            panes[indexPane].ZOrderIndex = floatWindows[i].ZOrderIndex;
+                    }
+                }
+
+                // sort IDockContent by its Pane's ZOrder
+                int[] sortedContents = null;
+                if (contents.Length > 0)
+                {
+                    sortedContents = new int[contents.Length];
+                    for (int i = 0; i < contents.Length; i++)
+                        sortedContents[i] = i;
+
+                    int lastDocument = contents.Length;
+                    for (int i = 0; i < contents.Length - 1; i++)
+                    {
+                        for (int j = i + 1; j < contents.Length; j++)
+                        {
+                            DockPane pane1 = dockPanel.Contents[sortedContents[i]].DockHandler.Pane;
+                            int ZOrderIndex1 = pane1 == null ? 0 : panes[dockPanel.Panes.IndexOf(pane1)].ZOrderIndex;
+                            DockPane pane2 = dockPanel.Contents[sortedContents[j]].DockHandler.Pane;
+                            int ZOrderIndex2 = pane2 == null ? 0 : panes[dockPanel.Panes.IndexOf(pane2)].ZOrderIndex;
+                            if (ZOrderIndex1 > ZOrderIndex2)
+                            {
+                                int temp = sortedContents[i];
+                                sortedContents[i] = sortedContents[j];
+                                sortedContents[j] = temp;
+                            }
+                        }
+                    }
+                }
+
+                // show non-document IDockContent first to avoid screen flickers
+                for (int i = 0; i < contents.Length; i++)
+                {
+                    IDockContent content = dockPanel.Contents[sortedContents[i]];
+                    if (content.DockHandler.Pane != null && content.DockHandler.Pane.DockState != DockState.Document)
+                        content.DockHandler.IsHidden = contents[sortedContents[i]].IsHidden;
+                }
+
+                // after all non-document IDockContent, show document IDockContent
+                for (int i = 0; i < contents.Length; i++)
+                {
+                    IDockContent content = dockPanel.Contents[sortedContents[i]];
+                    if (content.DockHandler.Pane != null && content.DockHandler.Pane.DockState == DockState.Document)
+                        content.DockHandler.IsHidden = contents[sortedContents[i]].IsHidden;
+                }
+
+                for (int i = 0; i < panes.Length; i++)
+                    dockPanel.Panes[i].ActiveContent = panes[i].IndexActiveContent == -1 ? null : dockPanel.Contents[panes[i].IndexActiveContent];
+
+                if (dockPanelStruct.IndexActiveDocumentPane != -1)
+                    dockPanel.Panes[dockPanelStruct.IndexActiveDocumentPane].Activate();
+
+                if (dockPanelStruct.IndexActivePane != -1)
+                    dockPanel.Panes[dockPanelStruct.IndexActivePane].Activate();
+
+                for (int i = dockPanel.Contents.Count - 1; i >= 0; i--)
+                    if (dockPanel.Contents[i] is DummyContent)
+                        dockPanel.Contents[i].DockHandler.Form.Close();
+
+                dockPanel.ResumeLayout(true, true);
+            }
+
+            private static bool MoveToNextElement(XmlTextReader xmlIn)
+            {
+                if (!xmlIn.Read())
+                    return false;
+
+                while (xmlIn.NodeType == XmlNodeType.EndElement)
+                {
+                    if (!xmlIn.Read())
+                        return false;
+                }
+
+                return true;
+            }
+
+            private static bool IsFormatVersionValid(string formatVersion)
+            {
+                if (formatVersion == ConfigFileVersion)
+                    return true;
+
+                foreach (string s in CompatibleConfigFileVersions)
+                    if (s == formatVersion)
+                        return true;
+
+                return false;
+            }
+        }
+
+        public void SaveAsXml(string fileName)
+        {
+            Persistor.SaveAsXml(this, fileName);
+        }
+
+        public void SaveAsXml(string fileName, Encoding encoding)
+        {
+            Persistor.SaveAsXml(this, fileName, encoding);
+        }
+
+        public void SaveAsXml(Stream stream, Encoding encoding)
+        {
+            Persistor.SaveAsXml(this, stream, encoding);
+        }
+
+        public void SaveAsXml(Stream stream, Encoding encoding, bool upstream)
+        {
+            Persistor.SaveAsXml(this, stream, encoding, upstream);
+        }
+
+        public void LoadFromXml(string fileName, DeserializeDockContent deserializeContent)
+        {
+            Persistor.LoadFromXml(this, fileName, deserializeContent);
+        }
+
+        public void LoadFromXml(Stream stream, DeserializeDockContent deserializeContent)
+        {
+            Persistor.LoadFromXml(this, stream, deserializeContent);
+        }
+
+        public void LoadFromXml(Stream stream, DeserializeDockContent deserializeContent, bool closeStream)
+        {
+            Persistor.LoadFromXml(this, stream, deserializeContent, closeStream);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.SplitterDragHandler.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.SplitterDragHandler.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.SplitterDragHandler.cs	(revision 2645)
@@ -0,0 +1,165 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    partial class DockPanel
+    {
+        private sealed class SplitterDragHandler : DragHandler
+        {
+            private class SplitterOutline
+            {
+                public SplitterOutline()
+                {
+                    m_dragForm = new DragForm();
+                    SetDragForm(Rectangle.Empty);
+                    DragForm.BackColor = Color.Black;
+                    DragForm.Opacity = 0.7;
+                    DragForm.Show(false);
+                }
+
+                DragForm m_dragForm;
+                private DragForm DragForm
+                {
+                    get { return m_dragForm; }
+                }
+
+                public void Show(Rectangle rect)
+                {
+                    SetDragForm(rect);
+                }
+
+                public void Close()
+                {
+                    DragForm.Close();
+                }
+
+                private void SetDragForm(Rectangle rect)
+                {
+                    DragForm.Bounds = rect;
+                    if (rect == Rectangle.Empty)
+                        DragForm.Region = new Region(Rectangle.Empty);
+                    else if (DragForm.Region != null)
+                        DragForm.Region = null;
+                }
+            }
+
+            public SplitterDragHandler(DockPanel dockPanel)
+                : base(dockPanel)
+            {
+            }
+
+            public new ISplitterDragSource DragSource
+            {
+                get { return base.DragSource as ISplitterDragSource; }
+                private set { base.DragSource = value; }
+            }
+
+            private SplitterOutline m_outline;
+            private SplitterOutline Outline
+            {
+                get { return m_outline; }
+                set { m_outline = value; }
+            }
+
+            private Rectangle m_rectSplitter;
+            private Rectangle RectSplitter
+            {
+                get { return m_rectSplitter; }
+                set { m_rectSplitter = value; }
+            }
+
+            public void BeginDrag(ISplitterDragSource dragSource, Rectangle rectSplitter)
+            {
+                DragSource = dragSource;
+                RectSplitter = rectSplitter;
+
+                if (!BeginDrag())
+                {
+                    DragSource = null;
+                    return;
+                }
+
+                Outline = new SplitterOutline();
+                Outline.Show(rectSplitter);
+                DragSource.BeginDrag(rectSplitter);
+            }
+
+            protected override void OnDragging()
+            {
+                Outline.Show(GetSplitterOutlineBounds(Control.MousePosition));
+            }
+
+            protected override void OnEndDrag(bool abort)
+            {
+                DockPanel.SuspendLayout(true);
+
+                Outline.Close();
+
+                if (!abort)
+                    DragSource.MoveSplitter(GetMovingOffset(Control.MousePosition));
+
+                DragSource.EndDrag();
+                DockPanel.ResumeLayout(true, true);
+            }
+
+            private int GetMovingOffset(Point ptMouse)
+            {
+                Rectangle rect = GetSplitterOutlineBounds(ptMouse);
+                if (DragSource.IsVertical)
+                    return rect.X - RectSplitter.X;
+                else
+                    return rect.Y - RectSplitter.Y;
+            }
+
+            private Rectangle GetSplitterOutlineBounds(Point ptMouse)
+            {
+                Rectangle rectLimit = DragSource.DragLimitBounds;
+
+                Rectangle rect = RectSplitter;
+                if (rectLimit.Width <= 0 || rectLimit.Height <= 0)
+                    return rect;
+
+                if (DragSource.IsVertical)
+                {
+                    rect.X += ptMouse.X - StartMousePosition.X;
+                    rect.Height = rectLimit.Height;
+                }
+                else
+                {
+                    rect.Y += ptMouse.Y - StartMousePosition.Y;
+                    rect.Width = rectLimit.Width;
+                }
+
+                if (rect.Left < rectLimit.Left)
+                    rect.X = rectLimit.X;
+                if (rect.Top < rectLimit.Top)
+                    rect.Y = rectLimit.Y;
+                if (rect.Right > rectLimit.Right)
+                    rect.X -= rect.Right - rectLimit.Right;
+                if (rect.Bottom > rectLimit.Bottom)
+                    rect.Y -= rect.Bottom - rectLimit.Bottom;
+
+                return rect;
+            }
+        }
+
+        private SplitterDragHandler m_splitterDragHandler = null;
+        private SplitterDragHandler GetSplitterDragHandler()
+        {
+            if (m_splitterDragHandler == null)
+                m_splitterDragHandler = new SplitterDragHandler(this);
+            return m_splitterDragHandler;
+        }
+
+        internal void BeginDrag(ISplitterDragSource dragSource, Rectangle rectSplitter)
+        {
+            GetSplitterDragHandler().BeginDrag(dragSource, rectSplitter);
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanel.cs	(revision 2645)
@@ -0,0 +1,1028 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.IO;
+using System.Text;
+using System.Diagnostics.CodeAnalysis;
+using System.Collections.Generic;
+
+// To simplify the process of finding the toolbox bitmap resource:
+// #1 Create an internal class called "resfinder" outside of the root namespace.
+// #2 Use "resfinder" in the toolbox bitmap attribute instead of the control name.
+// #3 use the "<default namespace>.<resourcename>" string to locate the resource.
+// See: http://www.bobpowell.net/toolboxbitmap.htm
+internal class resfinder
+{
+}
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "0#")]
+	public delegate IDockContent DeserializeDockContent(string persistString);
+
+    [LocalizedDescription("DockPanel_Description")]
+    [Designer(typeof(System.Windows.Forms.Design.ControlDesigner))]
+    [ToolboxBitmap(typeof(resfinder), "WeifenLuo.WinFormsUI.Docking.DockPanel.bmp")]
+    [DefaultProperty("DocumentStyle")]
+    [DefaultEvent("ActiveContentChanged")]
+	public partial class DockPanel : Panel
+	{
+        private FocusManagerImpl m_focusManager;
+        private DockPanelExtender m_extender;
+        private DockPaneCollection m_panes;
+        private FloatWindowCollection m_floatWindows;
+        private AutoHideWindowControl m_autoHideWindow;
+        private DockWindowCollection m_dockWindows;
+        private DockContent m_dummyContent; 
+        private Control m_dummyControl;
+        
+		public DockPanel()
+		{
+            m_focusManager = new FocusManagerImpl(this);
+			m_extender = new DockPanelExtender(this);
+			m_panes = new DockPaneCollection();
+			m_floatWindows = new FloatWindowCollection();
+
+            SuspendLayout();
+
+			m_autoHideWindow = new AutoHideWindowControl(this);
+			m_autoHideWindow.Visible = false;
+            SetAutoHideWindowParent();
+
+			m_dummyControl = new DummyControl();
+			m_dummyControl.Bounds = new Rectangle(0, 0, 1, 1);
+			Controls.Add(m_dummyControl);
+
+			m_dockWindows = new DockWindowCollection(this);
+			Controls.AddRange(new Control[]	{
+				DockWindows[DockState.Document],
+				DockWindows[DockState.DockLeft],
+				DockWindows[DockState.DockRight],
+				DockWindows[DockState.DockTop],
+				DockWindows[DockState.DockBottom]
+				});
+
+			m_dummyContent = new DockContent();
+            ResumeLayout();
+        }
+        
+        private Color m_BackColor;
+        /// <summary>
+        /// Determines the color with which the client rectangle will be drawn.
+        /// If you take this property instead of the BackColor it will not have any influence on the borders to the surrounding controls (DockPane).
+        /// If you use BackColor the borders to the surrounding controls (DockPane) will also change there colors.
+        /// Alternatively you can use both of them (BackColor to draw the define the color of the borders and DockBackColor to define the color of the client rectangle). 
+        /// For Backgroundimages: Set your prefered Image, then set the DockBackColor and the BackColor to the same Color (Control)
+        /// </summary>
+        public Color DockBackColor
+        {
+            get
+            {
+                return !m_BackColor.IsEmpty ? m_BackColor : base.BackColor;
+            }
+            set
+            {
+                m_BackColor = value;
+            }
+        }
+
+		private AutoHideStripBase m_autoHideStripControl = null;
+		internal AutoHideStripBase AutoHideStripControl
+		{
+			get
+			{	
+				if (m_autoHideStripControl == null)
+				{
+					m_autoHideStripControl = AutoHideStripFactory.CreateAutoHideStrip(this);
+					Controls.Add(m_autoHideStripControl);
+				}
+				return m_autoHideStripControl;
+			}
+		}
+        internal void ResetAutoHideStripControl()
+        {
+            if (m_autoHideStripControl != null)
+                m_autoHideStripControl.Dispose();
+
+            m_autoHideStripControl = null;
+        }
+
+		private void MdiClientHandleAssigned(object sender, EventArgs e)
+		{
+			SetMdiClient();
+			PerformLayout();
+		}
+
+		private void MdiClient_Layout(object sender, LayoutEventArgs e)
+		{
+			if (DocumentStyle != DocumentStyle.DockingMdi)
+				return;
+
+			foreach (DockPane pane in Panes)
+				if (pane.DockState == DockState.Document)
+					pane.SetContentBounds();
+
+			InvalidateWindowRegion();
+		}
+
+		private bool m_disposed = false;
+		protected override void Dispose(bool disposing)
+		{
+			lock (this)
+			{
+				if (!m_disposed && disposing)
+				{
+                    m_focusManager.Dispose();
+					if (m_mdiClientController != null)
+					{
+						m_mdiClientController.HandleAssigned -= new EventHandler(MdiClientHandleAssigned);
+						m_mdiClientController.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate);
+						m_mdiClientController.Layout -= new LayoutEventHandler(MdiClient_Layout);
+						m_mdiClientController.Dispose();
+					}
+					FloatWindows.Dispose();
+					Panes.Dispose();
+					DummyContent.Dispose();
+
+					m_disposed = true;
+				}
+				
+				base.Dispose(disposing);
+			}
+		}
+
+		[Browsable(false)]
+		public IDockContent ActiveAutoHideContent
+		{
+			get	{	return AutoHideWindow.ActiveContent;	}
+			set	{	AutoHideWindow.ActiveContent = value;	}
+		}
+
+        private bool m_allowEndUserDocking = true;
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_AllowEndUserDocking_Description")]
+		[DefaultValue(true)]
+		public bool AllowEndUserDocking
+		{
+			get	{	return m_allowEndUserDocking;	}
+			set	{	m_allowEndUserDocking = value;	}
+		}
+
+        private bool m_allowEndUserNestedDocking = true;
+        [LocalizedCategory("Category_Docking")]
+        [LocalizedDescription("DockPanel_AllowEndUserNestedDocking_Description")]
+        [DefaultValue(true)]
+        public bool AllowEndUserNestedDocking
+        {
+            get { return m_allowEndUserNestedDocking; }
+            set { m_allowEndUserNestedDocking = value; }
+        }
+
+        private DockContentCollection m_contents = new DockContentCollection();
+		[Browsable(false)]
+		public DockContentCollection Contents
+		{
+			get	{	return m_contents;	}
+		}
+
+		internal DockContent DummyContent
+		{
+			get	{	return m_dummyContent;	}
+		}
+
+        private bool m_rightToLeftLayout = false;
+        [DefaultValue(false)]
+        [LocalizedCategory("Appearance")]
+        [LocalizedDescription("DockPanel_RightToLeftLayout_Description")]
+        public bool RightToLeftLayout
+        {
+            get { return m_rightToLeftLayout; }
+            set
+            {
+                if (m_rightToLeftLayout == value)
+                    return;
+
+                m_rightToLeftLayout = value;
+                foreach (FloatWindow floatWindow in FloatWindows)
+                    floatWindow.RightToLeftLayout = value;
+            }
+        }
+
+        protected override void OnRightToLeftChanged(EventArgs e)
+        {
+            base.OnRightToLeftChanged(e);
+            foreach (FloatWindow floatWindow in FloatWindows)
+            {
+                if (floatWindow.RightToLeft != RightToLeft)
+                    floatWindow.RightToLeft = RightToLeft;
+            }
+        }
+
+		private bool m_showDocumentIcon = false;
+		[DefaultValue(false)]
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_ShowDocumentIcon_Description")]
+		public bool ShowDocumentIcon
+		{
+			get	{	return m_showDocumentIcon;	}
+			set
+			{
+				if (m_showDocumentIcon == value)
+					return;
+
+				m_showDocumentIcon = value;
+				Refresh();
+			}
+		}
+
+        private DockPanelSkin m_dockPanelSkin = new DockPanelSkin();
+        [LocalizedCategory("Category_Docking")]
+        [LocalizedDescription("DockPanel_DockPanelSkin")]
+        public DockPanelSkin Skin
+        {
+            get { return m_dockPanelSkin; }
+            set { m_dockPanelSkin = value; }
+        }
+
+        private DocumentTabStripLocation m_documentTabStripLocation = DocumentTabStripLocation.Top;
+        [DefaultValue(DocumentTabStripLocation.Top)]
+        [LocalizedCategory("Category_Docking")]
+        [LocalizedDescription("DockPanel_DocumentTabStripLocation")]
+        public DocumentTabStripLocation DocumentTabStripLocation
+        {
+            get { return m_documentTabStripLocation; }
+            set { m_documentTabStripLocation = value; }
+        }
+
+		[Browsable(false)]
+		public DockPanelExtender Extender
+		{
+			get	{	return m_extender;	}
+		}
+
+		public DockPanelExtender.IDockPaneFactory DockPaneFactory
+		{
+			get	{	return Extender.DockPaneFactory;	}
+		}
+
+		public DockPanelExtender.IFloatWindowFactory FloatWindowFactory
+		{
+			get	{	return Extender.FloatWindowFactory;	}
+		}
+
+		internal DockPanelExtender.IDockPaneCaptionFactory DockPaneCaptionFactory
+		{
+			get	{	return Extender.DockPaneCaptionFactory;	}
+		}
+
+		internal DockPanelExtender.IDockPaneStripFactory DockPaneStripFactory
+		{
+			get	{	return Extender.DockPaneStripFactory;	}
+		}
+
+		internal DockPanelExtender.IAutoHideStripFactory AutoHideStripFactory
+		{
+			get	{	return Extender.AutoHideStripFactory;	}
+		}
+
+		[Browsable(false)]
+		public DockPaneCollection Panes
+		{
+			get	{	return m_panes;	}
+		}
+
+		internal Rectangle DockArea
+		{
+			get
+			{
+				return new Rectangle(DockPadding.Left, DockPadding.Top,
+					ClientRectangle.Width - DockPadding.Left - DockPadding.Right,
+					ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom);
+			}
+		}
+
+		private double m_dockBottomPortion = 0.25;
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_DockBottomPortion_Description")]
+		[DefaultValue(0.25)]
+		public double DockBottomPortion
+		{
+			get	{	return m_dockBottomPortion;	}
+			set
+			{
+				if (value <= 0)
+					throw new ArgumentOutOfRangeException("value");
+
+				if (value == m_dockBottomPortion)
+					return;
+
+				m_dockBottomPortion = value;
+
+                if (m_dockBottomPortion < 1 && m_dockTopPortion < 1)
+                {
+                    if (m_dockTopPortion + m_dockBottomPortion > 1)
+                        m_dockTopPortion = 1 - m_dockBottomPortion;
+                }
+
+				PerformLayout();
+			}
+		}
+
+		private double m_dockLeftPortion = 0.25;
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_DockLeftPortion_Description")]
+		[DefaultValue(0.25)]
+		public double DockLeftPortion
+		{
+			get	{	return m_dockLeftPortion;	}
+			set
+			{
+				if (value <= 0)
+					throw new ArgumentOutOfRangeException("value");
+
+				if (value == m_dockLeftPortion)
+					return;
+
+				m_dockLeftPortion = value;
+
+                if (m_dockLeftPortion < 1 && m_dockRightPortion < 1)
+                {
+                    if (m_dockLeftPortion + m_dockRightPortion > 1)
+                        m_dockRightPortion = 1 - m_dockLeftPortion;
+                }
+				PerformLayout();
+			}
+		}
+
+		private double m_dockRightPortion = 0.25;
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_DockRightPortion_Description")]
+		[DefaultValue(0.25)]
+		public double DockRightPortion
+		{
+			get	{	return m_dockRightPortion;	}
+			set
+			{
+				if (value <= 0)
+					throw new ArgumentOutOfRangeException("value");
+
+				if (value == m_dockRightPortion)
+					return;
+
+				m_dockRightPortion = value;
+
+                if (m_dockLeftPortion < 1 && m_dockRightPortion < 1)
+                {
+                    if (m_dockLeftPortion + m_dockRightPortion > 1)
+                        m_dockLeftPortion = 1 - m_dockRightPortion;
+                }
+				PerformLayout();
+			}
+		}
+
+		private double m_dockTopPortion = 0.25;
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_DockTopPortion_Description")]
+		[DefaultValue(0.25)]
+		public double DockTopPortion
+		{
+			get	{	return m_dockTopPortion;	}
+			set
+			{
+				if (value <= 0)
+					throw new ArgumentOutOfRangeException("value");
+
+				if (value == m_dockTopPortion)
+					return;
+
+				m_dockTopPortion = value;
+
+                if (m_dockTopPortion < 1 && m_dockBottomPortion < 1)
+                {
+                    if (m_dockTopPortion + m_dockBottomPortion > 1)
+                        m_dockBottomPortion = 1 - m_dockTopPortion;
+                }
+				PerformLayout();
+			}
+		}
+
+		[Browsable(false)]
+		public DockWindowCollection DockWindows
+		{
+			get	{	return m_dockWindows;	}
+		}
+
+        public void UpdateDockWindowZOrder(DockStyle dockStyle, bool fullPanelEdge)
+        {
+            if (dockStyle == DockStyle.Left)
+            {
+                if (fullPanelEdge)
+                    DockWindows[DockState.DockLeft].SendToBack();
+                else
+                    DockWindows[DockState.DockLeft].BringToFront();
+            }
+            else if (dockStyle == DockStyle.Right)
+            {
+                if (fullPanelEdge)
+                    DockWindows[DockState.DockRight].SendToBack();
+                else
+                    DockWindows[DockState.DockRight].BringToFront();
+            }
+            else if (dockStyle == DockStyle.Top)
+            {
+                if (fullPanelEdge)
+                    DockWindows[DockState.DockTop].SendToBack();
+                else
+                    DockWindows[DockState.DockTop].BringToFront();
+            }
+            else if (dockStyle == DockStyle.Bottom)
+            {
+                if (fullPanelEdge)
+                    DockWindows[DockState.DockBottom].SendToBack();
+                else
+                    DockWindows[DockState.DockBottom].BringToFront();
+            }
+        }
+
+        public int DocumentsCount
+        {
+            get
+            {
+                int count = 0;
+                foreach (IDockContent content in Documents)
+                    count++;
+
+                return count;
+            }
+        }
+
+        public IDockContent[] DocumentsToArray()
+        {
+            int count = DocumentsCount;
+            IDockContent[] documents = new IDockContent[count];
+            int i = 0;
+            foreach (IDockContent content in Documents)
+            {
+                documents[i] = content;
+                i++;
+            }
+
+            return documents;
+        }
+
+		public IEnumerable<IDockContent> Documents
+		{
+            get
+            {
+                foreach (IDockContent content in Contents)
+                {
+                    if (content.DockHandler.DockState == DockState.Document)
+                        yield return content;
+                }
+            }
+		}
+
+		private Rectangle DocumentRectangle
+		{
+			get
+			{
+				Rectangle rect = DockArea;
+				if (DockWindows[DockState.DockLeft].VisibleNestedPanes.Count != 0)
+				{
+					rect.X += (int)(DockArea.Width * DockLeftPortion);
+					rect.Width -= (int)(DockArea.Width * DockLeftPortion);
+				}
+				if (DockWindows[DockState.DockRight].VisibleNestedPanes.Count != 0)
+					rect.Width -= (int)(DockArea.Width * DockRightPortion);
+				if (DockWindows[DockState.DockTop].VisibleNestedPanes.Count != 0)
+				{
+					rect.Y += (int)(DockArea.Height * DockTopPortion);
+					rect.Height -= (int)(DockArea.Height * DockTopPortion);
+				}
+				if (DockWindows[DockState.DockBottom].VisibleNestedPanes.Count != 0)
+					rect.Height -= (int)(DockArea.Height * DockBottomPortion);
+
+				return rect;
+			}
+		}
+
+		private Control DummyControl
+		{
+			get	{	return m_dummyControl;	}
+		}
+
+		[Browsable(false)]
+		public FloatWindowCollection FloatWindows
+		{
+			get	{	return m_floatWindows;	}
+		}
+
+        private Size m_defaultFloatWindowSize = new Size(300, 300);
+        [Category("Layout")]
+        [LocalizedDescription("DockPanel_DefaultFloatWindowSize_Description")]
+        public Size DefaultFloatWindowSize
+        {
+            get { return m_defaultFloatWindowSize; }
+            set { m_defaultFloatWindowSize = value; }
+        }
+        private bool ShouldSerializeDefaultFloatWindowSize()
+        {
+            return DefaultFloatWindowSize != new Size(300, 300);
+        }
+
+		private DocumentStyle m_documentStyle = DocumentStyle.DockingMdi;
+		[LocalizedCategory("Category_Docking")]
+		[LocalizedDescription("DockPanel_DocumentStyle_Description")]
+		[DefaultValue(DocumentStyle.DockingMdi)]
+		public DocumentStyle DocumentStyle
+		{
+			get	{	return m_documentStyle;	}
+			set
+			{
+				if (value == m_documentStyle)
+					return;
+
+				if (!Enum.IsDefined(typeof(DocumentStyle), value))
+					throw new InvalidEnumArgumentException();
+
+				if (value == DocumentStyle.SystemMdi && DockWindows[DockState.Document].VisibleNestedPanes.Count > 0)
+					throw new InvalidEnumArgumentException();
+
+				m_documentStyle = value;
+
+				SuspendLayout(true);
+
+                SetAutoHideWindowParent();
+				SetMdiClient();
+				InvalidateWindowRegion();
+
+				foreach (IDockContent content in Contents)
+				{
+					if (content.DockHandler.DockState == DockState.Document)
+						content.DockHandler.SetPaneAndVisible(content.DockHandler.Pane);
+				}
+
+                PerformMdiClientLayout();
+
+				ResumeLayout(true, true);
+			}
+		}
+
+        private int GetDockWindowSize(DockState dockState)
+        {
+            if (dockState == DockState.DockLeft || dockState == DockState.DockRight)
+            {
+                int width = ClientRectangle.Width - DockPadding.Left - DockPadding.Right;
+                int dockLeftSize = m_dockLeftPortion >= 1 ? (int)m_dockLeftPortion : (int)(width * m_dockLeftPortion);
+                int dockRightSize = m_dockRightPortion >= 1 ? (int)m_dockRightPortion : (int)(width * m_dockRightPortion);
+
+                if (dockLeftSize < MeasurePane.MinSize)
+                    dockLeftSize = MeasurePane.MinSize;
+                if (dockRightSize < MeasurePane.MinSize)
+                    dockRightSize = MeasurePane.MinSize;
+
+                if (dockLeftSize + dockRightSize > width - MeasurePane.MinSize)
+                {
+                    int adjust = (dockLeftSize + dockRightSize) - (width - MeasurePane.MinSize);
+                    dockLeftSize -= adjust / 2;
+                    dockRightSize -= adjust / 2;
+                }
+
+                return dockState == DockState.DockLeft ? dockLeftSize : dockRightSize;
+            }
+            else if (dockState == DockState.DockTop || dockState == DockState.DockBottom)
+            {
+                int height = ClientRectangle.Height - DockPadding.Top - DockPadding.Bottom;
+                int dockTopSize = m_dockTopPortion >= 1 ? (int)m_dockTopPortion : (int)(height * m_dockTopPortion);
+                int dockBottomSize = m_dockBottomPortion >= 1 ? (int)m_dockBottomPortion : (int)(height * m_dockBottomPortion);
+
+                if (dockTopSize < MeasurePane.MinSize)
+                    dockTopSize = MeasurePane.MinSize;
+                if (dockBottomSize < MeasurePane.MinSize)
+                    dockBottomSize = MeasurePane.MinSize;
+
+                if (dockTopSize + dockBottomSize > height - MeasurePane.MinSize)
+                {
+                    int adjust = (dockTopSize + dockBottomSize) - (height - MeasurePane.MinSize);
+                    dockTopSize -= adjust / 2;
+                    dockBottomSize -= adjust / 2;
+                }
+
+                return dockState == DockState.DockTop ? dockTopSize : dockBottomSize;
+            }
+            else
+                return 0;
+        }
+
+        protected override void OnLayout(LayoutEventArgs levent)
+		{
+			SuspendLayout(true);
+
+			AutoHideStripControl.Bounds = ClientRectangle;
+
+			CalculateDockPadding();
+
+            DockWindows[DockState.DockLeft].Width = GetDockWindowSize(DockState.DockLeft);
+			DockWindows[DockState.DockRight].Width = GetDockWindowSize(DockState.DockRight);
+			DockWindows[DockState.DockTop].Height = GetDockWindowSize(DockState.DockTop);
+			DockWindows[DockState.DockBottom].Height = GetDockWindowSize(DockState.DockBottom);
+
+			AutoHideWindow.Bounds = GetAutoHideWindowBounds(AutoHideWindowRectangle);
+
+			DockWindows[DockState.Document].BringToFront();
+			AutoHideWindow.BringToFront();
+
+			base.OnLayout(levent);
+
+            if (DocumentStyle == DocumentStyle.SystemMdi && MdiClientExists)
+            {
+                SetMdiClientBounds(SystemMdiClientBounds);
+                InvalidateWindowRegion();
+            }
+            else if (DocumentStyle == DocumentStyle.DockingMdi)
+                InvalidateWindowRegion();
+
+			ResumeLayout(true, true);
+		}
+
+		internal Rectangle GetTabStripRectangle(DockState dockState)
+		{
+			return AutoHideStripControl.GetTabStripRectangle(dockState);
+		}
+
+		protected override void OnPaint(PaintEventArgs e)
+		{
+			base.OnPaint(e);
+
+		    if (DockBackColor == BackColor) return;
+
+		    Graphics g = e.Graphics;
+		    SolidBrush bgBrush = new SolidBrush(DockBackColor);
+		    g.FillRectangle(bgBrush, ClientRectangle);
+		}
+
+		internal void AddContent(IDockContent content)
+		{
+			if (content == null)
+				throw(new ArgumentNullException());
+
+			if (!Contents.Contains(content))
+			{
+				Contents.Add(content);
+				OnContentAdded(new DockContentEventArgs(content));
+			}
+		}
+
+		internal void AddPane(DockPane pane)
+		{
+			if (Panes.Contains(pane))
+				return;
+
+			Panes.Add(pane);
+		}
+
+		internal void AddFloatWindow(FloatWindow floatWindow)
+		{
+			if (FloatWindows.Contains(floatWindow))
+				return;
+
+			FloatWindows.Add(floatWindow);
+		}
+
+		private void CalculateDockPadding()
+		{
+			DockPadding.All = 0;
+
+			int height = AutoHideStripControl.MeasureHeight();
+
+			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockLeftAutoHide) > 0)
+				DockPadding.Left = height;
+			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockRightAutoHide) > 0)
+				DockPadding.Right = height;
+			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockTopAutoHide) > 0)
+				DockPadding.Top = height;
+			if (AutoHideStripControl.GetNumberOfPanes(DockState.DockBottomAutoHide) > 0)
+				DockPadding.Bottom = height;
+		}
+
+		internal void RemoveContent(IDockContent content)
+		{
+			if (content == null)
+				throw(new ArgumentNullException());
+			
+			if (Contents.Contains(content))
+			{
+				Contents.Remove(content);
+				OnContentRemoved(new DockContentEventArgs(content));
+			}
+		}
+
+		internal void RemovePane(DockPane pane)
+		{
+			if (!Panes.Contains(pane))
+				return;
+
+			Panes.Remove(pane);
+		}
+
+		internal void RemoveFloatWindow(FloatWindow floatWindow)
+		{
+			if (!FloatWindows.Contains(floatWindow))
+				return;
+
+			FloatWindows.Remove(floatWindow);
+		}
+
+		public void SetPaneIndex(DockPane pane, int index)
+		{
+			int oldIndex = Panes.IndexOf(pane);
+			if (oldIndex == -1)
+				throw(new ArgumentException(Strings.DockPanel_SetPaneIndex_InvalidPane));
+
+			if (index < 0 || index > Panes.Count - 1)
+				if (index != -1)
+					throw(new ArgumentOutOfRangeException(Strings.DockPanel_SetPaneIndex_InvalidIndex));
+				
+			if (oldIndex == index)
+				return;
+			if (oldIndex == Panes.Count - 1 && index == -1)
+				return;
+
+			Panes.Remove(pane);
+			if (index == -1)
+				Panes.Add(pane);
+			else if (oldIndex < index)
+				Panes.AddAt(pane, index - 1);
+			else
+				Panes.AddAt(pane, index);
+		}
+
+		public void SuspendLayout(bool allWindows)
+		{
+            FocusManager.SuspendFocusTracking();
+			SuspendLayout();
+			if (allWindows)
+				SuspendMdiClientLayout();
+		}
+
+		public void ResumeLayout(bool performLayout, bool allWindows)
+		{
+            FocusManager.ResumeFocusTracking();
+            ResumeLayout(performLayout);
+            if (allWindows)
+                ResumeMdiClientLayout(performLayout);
+		}
+
+	    internal Form ParentForm
+		{
+			get
+			{	
+				if (!IsParentFormValid())
+					throw new InvalidOperationException(Strings.DockPanel_ParentForm_Invalid);
+
+				return GetMdiClientController().ParentForm;
+			}
+		}
+
+		private bool IsParentFormValid()
+		{
+			if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow)
+				return true;
+
+            if (!MdiClientExists)
+                GetMdiClientController().RenewMdiClient();
+
+            return (MdiClientExists);
+		}
+
+		protected override void OnParentChanged(EventArgs e)
+		{
+            SetAutoHideWindowParent();
+            GetMdiClientController().ParentForm = (this.Parent as Form);
+			base.OnParentChanged (e);
+		}
+
+        private void SetAutoHideWindowParent()
+        {
+            Control parent;
+            if (DocumentStyle == DocumentStyle.DockingMdi ||
+                DocumentStyle == DocumentStyle.SystemMdi)
+                parent = this.Parent;
+            else
+                parent = this;
+            if (AutoHideWindow.Parent != parent)
+            {
+                AutoHideWindow.Parent = parent;
+                AutoHideWindow.BringToFront();
+            }
+        }
+
+		protected override void OnVisibleChanged(EventArgs e)
+		{
+			base.OnVisibleChanged (e);
+
+			if (Visible)
+				SetMdiClient();
+		}
+
+		private Rectangle SystemMdiClientBounds
+		{
+			get
+			{
+				if (!IsParentFormValid() || !Visible)
+					return Rectangle.Empty;
+
+				Rectangle rect = ParentForm.RectangleToClient(RectangleToScreen(DocumentWindowBounds));
+				return rect;
+			}
+		}
+
+		internal Rectangle DocumentWindowBounds
+		{
+			get
+			{
+				Rectangle rectDocumentBounds = DisplayRectangle;
+				if (DockWindows[DockState.DockLeft].Visible)
+				{
+					rectDocumentBounds.X += DockWindows[DockState.DockLeft].Width;
+					rectDocumentBounds.Width -= DockWindows[DockState.DockLeft].Width;
+				}
+				if (DockWindows[DockState.DockRight].Visible)
+					rectDocumentBounds.Width -= DockWindows[DockState.DockRight].Width;
+				if (DockWindows[DockState.DockTop].Visible)
+				{
+					rectDocumentBounds.Y += DockWindows[DockState.DockTop].Height;
+					rectDocumentBounds.Height -= DockWindows[DockState.DockTop].Height;
+				}
+				if (DockWindows[DockState.DockBottom].Visible)
+					rectDocumentBounds.Height -= DockWindows[DockState.DockBottom].Height;
+
+				return rectDocumentBounds;
+
+			}
+		}
+
+        private PaintEventHandler m_dummyControlPaintEventHandler = null;
+        private void InvalidateWindowRegion()
+        {
+            if (DesignMode)
+                return;
+
+            if (m_dummyControlPaintEventHandler == null)
+                m_dummyControlPaintEventHandler = new PaintEventHandler(DummyControl_Paint);
+
+            DummyControl.Paint += m_dummyControlPaintEventHandler;
+            DummyControl.Invalidate();
+        }
+
+        void DummyControl_Paint(object sender, PaintEventArgs e)
+        {
+            DummyControl.Paint -= m_dummyControlPaintEventHandler;
+            UpdateWindowRegion();
+        }
+
+		private void UpdateWindowRegion()
+		{
+			if (this.DocumentStyle == DocumentStyle.DockingMdi)
+				UpdateWindowRegion_ClipContent();
+			else if (this.DocumentStyle == DocumentStyle.DockingSdi ||
+				this.DocumentStyle == DocumentStyle.DockingWindow)
+				UpdateWindowRegion_FullDocumentArea();
+			else if (this.DocumentStyle == DocumentStyle.SystemMdi)
+				UpdateWindowRegion_EmptyDocumentArea();
+		}
+
+		private void UpdateWindowRegion_FullDocumentArea()
+		{
+			SetRegion(null);
+		}
+
+		private void UpdateWindowRegion_EmptyDocumentArea()
+		{
+			Rectangle rect = DocumentWindowBounds;
+			SetRegion(new Rectangle[] { rect });
+		}
+
+		private void UpdateWindowRegion_ClipContent()
+		{
+			int count = 0;
+			foreach (DockPane pane in this.Panes)
+			{
+				if (!pane.Visible || pane.DockState != DockState.Document)
+					continue;
+
+				count ++;
+			}
+
+            if (count == 0)
+            {
+                SetRegion(null);
+                return;
+            }
+
+			Rectangle[] rects = new Rectangle[count];
+			int i = 0;
+			foreach (DockPane pane in this.Panes)
+			{
+				if (!pane.Visible || pane.DockState != DockState.Document)
+					continue;
+
+                rects[i] = RectangleToClient(pane.RectangleToScreen(pane.ContentRectangle));
+				i++;
+			}
+
+			SetRegion(rects);
+		}
+
+		private Rectangle[] m_clipRects = null;
+		private void SetRegion(Rectangle[] clipRects)
+		{
+			if (!IsClipRectsChanged(clipRects))
+				return;
+
+			m_clipRects = clipRects;
+
+			if (m_clipRects == null || m_clipRects.GetLength(0) == 0)
+				Region = null;
+			else
+			{
+				Region region = new Region(new Rectangle(0, 0, this.Width, this.Height));
+				foreach (Rectangle rect in m_clipRects)
+					region.Exclude(rect);
+				Region = region;
+			}
+		}
+
+		private bool IsClipRectsChanged(Rectangle[] clipRects)
+		{
+			if (clipRects == null && m_clipRects == null)
+				return false;
+			else if ((clipRects == null) != (m_clipRects == null))
+				return true;
+
+			foreach (Rectangle rect in clipRects)
+			{
+				bool matched = false;
+				foreach (Rectangle rect2 in m_clipRects)
+				{
+					if (rect == rect2)
+					{
+						matched = true;
+						break;
+					}
+				}
+				if (!matched)
+					return true;
+			}
+
+			foreach (Rectangle rect2 in m_clipRects)
+			{
+				bool matched = false;
+				foreach (Rectangle rect in clipRects)
+				{
+					if (rect == rect2)
+					{
+						matched = true;
+						break;
+					}
+				}
+				if (!matched)
+					return true;
+			}
+			return false;
+		}
+
+		private static readonly object ContentAddedEvent = new object();
+		[LocalizedCategory("Category_DockingNotification")]
+		[LocalizedDescription("DockPanel_ContentAdded_Description")]
+		public event EventHandler<DockContentEventArgs> ContentAdded
+		{
+			add	{	Events.AddHandler(ContentAddedEvent, value);	}
+			remove	{	Events.RemoveHandler(ContentAddedEvent, value);	}
+		}
+		protected virtual void OnContentAdded(DockContentEventArgs e)
+		{
+			EventHandler<DockContentEventArgs> handler = (EventHandler<DockContentEventArgs>)Events[ContentAddedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+
+		private static readonly object ContentRemovedEvent = new object();
+		[LocalizedCategory("Category_DockingNotification")]
+		[LocalizedDescription("DockPanel_ContentRemoved_Description")]
+		public event EventHandler<DockContentEventArgs> ContentRemoved
+		{
+			add	{	Events.AddHandler(ContentRemovedEvent, value);	}
+			remove	{	Events.RemoveHandler(ContentRemovedEvent, value);	}
+		}
+		protected virtual void OnContentRemoved(DockContentEventArgs e)
+		{
+			EventHandler<DockContentEventArgs> handler = (EventHandler<DockContentEventArgs>)Events[ContentRemovedEvent];
+			if (handler != null)
+				handler(this, e);
+		}
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanelExtender.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanelExtender.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanelExtender.cs	(revision 2645)
@@ -0,0 +1,225 @@
+using System;
+using System.Drawing;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public sealed class DockPanelExtender
+	{
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        public interface IDockPaneFactory
+		{
+			DockPane CreateDockPane(IDockContent content, DockState visibleState, bool show);
+            [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")]            
+			DockPane CreateDockPane(IDockContent content, FloatWindow floatWindow, bool show);
+			DockPane CreateDockPane(IDockContent content, DockPane previousPane, DockAlignment alignment, double proportion, bool show);
+            [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "1#")]            
+			DockPane CreateDockPane(IDockContent content, Rectangle floatWindowBounds, bool show);
+		}
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        public interface IFloatWindowFactory
+		{
+			FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane);
+			FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds);
+		}
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        public interface IDockPaneCaptionFactory
+		{
+			DockPaneCaptionBase CreateDockPaneCaption(DockPane pane);
+		}
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        public interface IDockPaneStripFactory
+		{
+			DockPaneStripBase CreateDockPaneStrip(DockPane pane);
+		}
+
+        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
+        public interface IAutoHideStripFactory
+		{
+			AutoHideStripBase CreateAutoHideStrip(DockPanel panel);
+		}
+
+		#region DefaultDockPaneFactory
+		private class DefaultDockPaneFactory : IDockPaneFactory
+		{
+			public DockPane CreateDockPane(IDockContent content, DockState visibleState, bool show)
+			{
+				return new DockPane(content, visibleState, show);
+			}
+
+			public DockPane CreateDockPane(IDockContent content, FloatWindow floatWindow, bool show)
+			{
+				return new DockPane(content, floatWindow, show);
+			}
+
+			public DockPane CreateDockPane(IDockContent content, DockPane prevPane, DockAlignment alignment, double proportion, bool show)
+			{
+				return new DockPane(content, prevPane, alignment, proportion, show);
+			}
+
+			public DockPane CreateDockPane(IDockContent content, Rectangle floatWindowBounds, bool show)
+			{
+				return new DockPane(content, floatWindowBounds, show);
+			}
+		}
+		#endregion
+
+		#region DefaultFloatWindowFactory
+		private class DefaultFloatWindowFactory : IFloatWindowFactory
+		{
+			public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane)
+			{
+				return new FloatWindow(dockPanel, pane);
+			}
+
+			public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
+			{
+				return new FloatWindow(dockPanel, pane, bounds);
+			}
+		}
+		#endregion
+
+		#region DefaultDockPaneCaptionFactory
+		private class DefaultDockPaneCaptionFactory : IDockPaneCaptionFactory
+		{
+			public DockPaneCaptionBase CreateDockPaneCaption(DockPane pane)
+			{
+				return new VS2005DockPaneCaption(pane);
+			}
+		}
+		#endregion
+
+		#region DefaultDockPaneTabStripFactory
+		private class DefaultDockPaneStripFactory : IDockPaneStripFactory
+		{
+			public DockPaneStripBase CreateDockPaneStrip(DockPane pane)
+			{
+				return new VS2005DockPaneStrip(pane);
+			}
+		}
+		#endregion
+
+		#region DefaultAutoHideStripFactory
+		private class DefaultAutoHideStripFactory : IAutoHideStripFactory
+		{
+			public AutoHideStripBase CreateAutoHideStrip(DockPanel panel)
+			{
+				return new VS2005AutoHideStrip(panel);
+			}
+		}
+		#endregion
+
+		internal DockPanelExtender(DockPanel dockPanel)
+		{
+			m_dockPanel = dockPanel;
+		}
+
+		private DockPanel m_dockPanel;
+		private DockPanel DockPanel
+		{
+			get	{	return m_dockPanel;	}
+		}
+
+		private IDockPaneFactory m_dockPaneFactory = null;
+		public IDockPaneFactory DockPaneFactory
+		{
+			get
+			{
+				if (m_dockPaneFactory == null)
+					m_dockPaneFactory = new DefaultDockPaneFactory();
+
+				return m_dockPaneFactory;
+			}
+			set
+			{
+				if (DockPanel.Panes.Count > 0)
+					throw new InvalidOperationException();
+
+				m_dockPaneFactory = value;
+			}
+		}
+
+		private IFloatWindowFactory m_floatWindowFactory = null;
+		public IFloatWindowFactory FloatWindowFactory
+		{
+			get
+			{
+				if (m_floatWindowFactory == null)
+					m_floatWindowFactory = new DefaultFloatWindowFactory();
+
+				return m_floatWindowFactory;
+			}
+			set
+			{
+				if (DockPanel.FloatWindows.Count > 0)
+					throw new InvalidOperationException();
+
+				m_floatWindowFactory = value;
+			}
+		}
+
+		private IDockPaneCaptionFactory m_dockPaneCaptionFactory = null;
+		public IDockPaneCaptionFactory DockPaneCaptionFactory
+		{	
+			get
+			{
+				if (m_dockPaneCaptionFactory == null)
+					m_dockPaneCaptionFactory = new DefaultDockPaneCaptionFactory();
+
+				return m_dockPaneCaptionFactory;
+			}
+			set
+			{
+				if (DockPanel.Panes.Count > 0)
+					throw new InvalidOperationException();
+
+				m_dockPaneCaptionFactory = value;
+			}
+		}
+
+		private IDockPaneStripFactory m_dockPaneStripFactory = null;
+		public IDockPaneStripFactory DockPaneStripFactory
+		{
+			get
+			{
+				if (m_dockPaneStripFactory == null)
+					m_dockPaneStripFactory = new DefaultDockPaneStripFactory();
+
+				return m_dockPaneStripFactory;
+			}
+			set
+			{
+				if (DockPanel.Contents.Count > 0)
+					throw new InvalidOperationException();
+
+				m_dockPaneStripFactory = value;
+			}
+		}
+
+		private IAutoHideStripFactory m_autoHideStripFactory = null;
+		public IAutoHideStripFactory AutoHideStripFactory
+		{	
+			get
+			{
+				if (m_autoHideStripFactory == null)
+					m_autoHideStripFactory = new DefaultAutoHideStripFactory();
+
+				return m_autoHideStripFactory;
+			}
+			set
+			{
+				if (DockPanel.Contents.Count > 0)
+					throw new InvalidOperationException();
+
+				if (m_autoHideStripFactory == value)
+					return;
+
+				m_autoHideStripFactory = value;
+                DockPanel.ResetAutoHideStripControl();
+			}
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanelSkin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanelSkin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockPanelSkin.cs	(revision 2645)
@@ -0,0 +1,421 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Design;
+using System.Windows.Forms.Design;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    #region DockPanelSkin classes
+    /// <summary>
+    /// The skin to use when displaying the DockPanel.
+    /// The skin allows custom gradient color schemes to be used when drawing the
+    /// DockStrips and Tabs.
+    /// </summary>
+    [TypeConverter(typeof(DockPanelSkinConverter))]
+    public class DockPanelSkin
+    {
+        private AutoHideStripSkin m_autoHideStripSkin;
+        private DockPaneStripSkin m_dockPaneStripSkin;
+
+        public DockPanelSkin()
+        {
+            m_autoHideStripSkin = new AutoHideStripSkin();
+            m_dockPaneStripSkin = new DockPaneStripSkin();
+        }
+
+        /// <summary>
+        /// The skin used to display the auto hide strips and tabs.
+        /// </summary>
+        public AutoHideStripSkin AutoHideStripSkin
+        {
+            get { return m_autoHideStripSkin; }
+            set { m_autoHideStripSkin = value; }
+        }
+
+        /// <summary>
+        /// The skin used to display the Document and ToolWindow style DockStrips and Tabs.
+        /// </summary>
+        public DockPaneStripSkin DockPaneStripSkin
+        {
+            get { return m_dockPaneStripSkin; }
+            set { m_dockPaneStripSkin = value; }
+        }
+    }
+
+    /// <summary>
+    /// The skin used to display the auto hide strip and tabs.
+    /// </summary>
+    [TypeConverter(typeof(AutoHideStripConverter))]
+    public class AutoHideStripSkin
+    {
+        private DockPanelGradient m_dockStripGradient;
+        private TabGradient m_TabGradient;
+
+        public AutoHideStripSkin()
+        {
+            m_dockStripGradient = new DockPanelGradient();
+            m_dockStripGradient.StartColor = SystemColors.ControlLight;
+            m_dockStripGradient.EndColor = SystemColors.ControlLight;
+
+            m_TabGradient = new TabGradient();
+            m_TabGradient.TextColor = SystemColors.ControlDarkDark;
+        }
+
+        /// <summary>
+        /// The gradient color skin for the DockStrips.
+        /// </summary>
+        public DockPanelGradient DockStripGradient
+        {
+            get { return m_dockStripGradient; }
+            set { m_dockStripGradient = value; }
+        }
+
+        /// <summary>
+        /// The gradient color skin for the Tabs.
+        /// </summary>
+        public TabGradient TabGradient
+        {
+            get { return m_TabGradient; }
+            set { m_TabGradient = value; }
+        }
+    }
+
+    /// <summary>
+    /// The skin used to display the document and tool strips and tabs.
+    /// </summary>
+    [TypeConverter(typeof(DockPaneStripConverter))]
+    public class DockPaneStripSkin
+    {
+        private DockPaneStripGradient m_DocumentGradient;
+        private DockPaneStripToolWindowGradient m_ToolWindowGradient;
+
+        public DockPaneStripSkin()
+        {
+            m_DocumentGradient = new DockPaneStripGradient();
+            m_DocumentGradient.DockStripGradient.StartColor = SystemColors.Control;
+            m_DocumentGradient.DockStripGradient.EndColor = SystemColors.Control;
+            m_DocumentGradient.ActiveTabGradient.StartColor = SystemColors.ControlLightLight;
+            m_DocumentGradient.ActiveTabGradient.EndColor = SystemColors.ControlLightLight;
+            m_DocumentGradient.InactiveTabGradient.StartColor = SystemColors.ControlLight;
+            m_DocumentGradient.InactiveTabGradient.EndColor = SystemColors.ControlLight;
+
+            m_ToolWindowGradient = new DockPaneStripToolWindowGradient();
+            m_ToolWindowGradient.DockStripGradient.StartColor = SystemColors.ControlLight;
+            m_ToolWindowGradient.DockStripGradient.EndColor = SystemColors.ControlLight;
+            
+            m_ToolWindowGradient.ActiveTabGradient.StartColor = SystemColors.Control;
+            m_ToolWindowGradient.ActiveTabGradient.EndColor = SystemColors.Control;
+            
+            m_ToolWindowGradient.InactiveTabGradient.StartColor = Color.Transparent;
+            m_ToolWindowGradient.InactiveTabGradient.EndColor = Color.Transparent;
+            m_ToolWindowGradient.InactiveTabGradient.TextColor = SystemColors.ControlDarkDark;
+            
+            m_ToolWindowGradient.ActiveCaptionGradient.StartColor = SystemColors.GradientActiveCaption;
+            m_ToolWindowGradient.ActiveCaptionGradient.EndColor = SystemColors.ActiveCaption;
+            m_ToolWindowGradient.ActiveCaptionGradient.LinearGradientMode = LinearGradientMode.Vertical;
+            m_ToolWindowGradient.ActiveCaptionGradient.TextColor = SystemColors.ActiveCaptionText;
+
+            m_ToolWindowGradient.InactiveCaptionGradient.StartColor = SystemColors.GradientInactiveCaption;
+            m_ToolWindowGradient.InactiveCaptionGradient.EndColor = SystemColors.GradientInactiveCaption;
+            m_ToolWindowGradient.InactiveCaptionGradient.LinearGradientMode = LinearGradientMode.Vertical;
+            m_ToolWindowGradient.InactiveCaptionGradient.TextColor = SystemColors.ControlText;
+        }
+
+        /// <summary>
+        /// The skin used to display the Document style DockPane strip and tab.
+        /// </summary>
+        public DockPaneStripGradient DocumentGradient
+        {
+            get { return m_DocumentGradient; }
+            set { m_DocumentGradient = value; }
+        }
+
+        /// <summary>
+        /// The skin used to display the ToolWindow style DockPane strip and tab.
+        /// </summary>
+        public DockPaneStripToolWindowGradient ToolWindowGradient
+        {
+            get { return m_ToolWindowGradient; }
+            set { m_ToolWindowGradient = value; }
+        }
+    }
+
+    /// <summary>
+    /// The skin used to display the DockPane ToolWindow strip and tab.
+    /// </summary>
+    [TypeConverter(typeof(DockPaneStripGradientConverter))]
+    public class DockPaneStripToolWindowGradient : DockPaneStripGradient
+    {
+        private TabGradient m_activeCaptionGradient;
+        private TabGradient m_inactiveCaptionGradient;
+
+        public DockPaneStripToolWindowGradient()
+        {
+            m_activeCaptionGradient = new TabGradient();
+            m_inactiveCaptionGradient = new TabGradient();
+        }
+
+        /// <summary>
+        /// The skin used to display the active ToolWindow caption.
+        /// </summary>
+        public TabGradient ActiveCaptionGradient
+        {
+            get { return m_activeCaptionGradient; }
+            set { m_activeCaptionGradient = value; }
+        }
+
+        /// <summary>
+        /// The skin used to display the inactive ToolWindow caption.
+        /// </summary>
+        public TabGradient InactiveCaptionGradient
+        {
+            get { return m_inactiveCaptionGradient; }
+            set { m_inactiveCaptionGradient = value; }
+        }
+    }
+
+    /// <summary>
+    /// The skin used to display the DockPane strip and tab.
+    /// </summary>
+    [TypeConverter(typeof(DockPaneStripGradientConverter))]
+    public class DockPaneStripGradient
+    {
+        private DockPanelGradient m_dockStripGradient;
+        private TabGradient m_activeTabGradient;
+        private TabGradient m_inactiveTabGradient;
+
+        public DockPaneStripGradient()
+        {
+            m_dockStripGradient = new DockPanelGradient();
+            m_activeTabGradient = new TabGradient();
+            m_inactiveTabGradient = new TabGradient();
+        }
+
+        /// <summary>
+        /// The gradient color skin for the DockStrip.
+        /// </summary>
+        public DockPanelGradient DockStripGradient
+        {
+            get { return m_dockStripGradient; }
+            set { m_dockStripGradient = value; }
+        }
+
+        /// <summary>
+        /// The skin used to display the active DockPane tabs.
+        /// </summary>
+        public TabGradient ActiveTabGradient
+        {
+            get { return m_activeTabGradient; }
+            set { m_activeTabGradient = value; }
+        }
+
+        /// <summary>
+        /// The skin used to display the inactive DockPane tabs.
+        /// </summary>
+        public TabGradient InactiveTabGradient
+        {
+            get { return m_inactiveTabGradient; }
+            set { m_inactiveTabGradient = value; }
+        }
+    }
+
+    /// <summary>
+    /// The skin used to display the dock pane tab
+    /// </summary>
+    [TypeConverter(typeof(DockPaneTabGradientConverter))]
+    public class TabGradient : DockPanelGradient
+    {
+        private Color m_textColor;
+
+        public TabGradient()
+        {
+            m_textColor = SystemColors.ControlText;
+        }
+
+        /// <summary>
+        /// The text color.
+        /// </summary>
+        [DefaultValue(typeof(SystemColors), "ControlText")]
+        public Color TextColor
+        {
+            get { return m_textColor; }
+            set { m_textColor = value; }
+        }
+    }
+
+    /// <summary>
+    /// The gradient color skin.
+    /// </summary>
+    [TypeConverter(typeof(DockPanelGradientConverter))]
+    public class DockPanelGradient
+    {
+        private Color m_startColor;
+        private Color m_endColor;
+        private LinearGradientMode m_linearGradientMode;
+
+        public DockPanelGradient()
+        {
+            m_startColor = SystemColors.Control;
+            m_endColor = SystemColors.Control;
+            m_linearGradientMode = LinearGradientMode.Horizontal;
+        }
+
+        /// <summary>
+        /// The beginning gradient color.
+        /// </summary>
+        [DefaultValue(typeof(SystemColors), "Control")]
+        public Color StartColor
+        {
+            get { return m_startColor; }
+            set { m_startColor = value; }
+        }
+
+        /// <summary>
+        /// The ending gradient color.
+        /// </summary>
+        [DefaultValue(typeof(SystemColors), "Control")]
+        public Color EndColor
+        {
+            get { return m_endColor; }
+            set { m_endColor = value; }
+        }
+
+        /// <summary>
+        /// The gradient mode to display the colors.
+        /// </summary>
+        [DefaultValue(LinearGradientMode.Horizontal)]
+        public LinearGradientMode LinearGradientMode
+        {
+            get { return m_linearGradientMode; }
+            set { m_linearGradientMode = value; }
+        }
+    }
+
+    #endregion
+
+    #region Converters
+    public class DockPanelSkinConverter : ExpandableObjectConverter
+    {
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            if (destinationType == typeof(DockPanelSkin))
+                return true;
+
+            return base.CanConvertTo(context, destinationType);
+        }
+
+        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+        {
+            if (destinationType == typeof(String) && value is DockPanelSkin)
+            {
+                return "DockPanelSkin";
+            }
+            return base.ConvertTo(context, culture, value, destinationType);
+        }
+    }
+
+    public class DockPanelGradientConverter : ExpandableObjectConverter
+    {
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            if (destinationType == typeof(DockPanelGradient))
+                return true;
+
+            return base.CanConvertTo(context, destinationType);
+        }
+
+        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+        {
+            if (destinationType == typeof(String) && value is DockPanelGradient)
+            {
+                return "DockPanelGradient";
+            }
+            return base.ConvertTo(context, culture, value, destinationType);
+        }
+    }
+
+    public class AutoHideStripConverter : ExpandableObjectConverter
+    {
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            if (destinationType == typeof(AutoHideStripSkin))
+                return true;
+
+            return base.CanConvertTo(context, destinationType);
+        }
+
+        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+        {
+            if (destinationType == typeof(String) && value is AutoHideStripSkin)
+            {
+                return "AutoHideStripSkin";
+            }
+            return base.ConvertTo(context, culture, value, destinationType);
+        }
+    }
+
+    public class DockPaneStripConverter : ExpandableObjectConverter
+    {
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            if (destinationType == typeof(DockPaneStripSkin))
+                return true;
+
+            return base.CanConvertTo(context, destinationType);
+        }
+
+        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+        {
+            if (destinationType == typeof(String) && value is DockPaneStripSkin)
+            {
+                return "DockPaneStripSkin";
+            }
+            return base.ConvertTo(context, culture, value, destinationType);
+        }
+    }
+
+    public class DockPaneStripGradientConverter : ExpandableObjectConverter
+    {
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            if (destinationType == typeof(DockPaneStripGradient))
+                return true;
+
+            return base.CanConvertTo(context, destinationType);
+        }
+
+        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+        {
+            if (destinationType == typeof(String) && value is DockPaneStripGradient)
+            {
+                return "DockPaneStripGradient";
+            }
+            return base.ConvertTo(context, culture, value, destinationType);
+        }
+    }
+
+    public class DockPaneTabGradientConverter : ExpandableObjectConverter
+    {
+        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+        {
+            if (destinationType == typeof(TabGradient))
+                return true;
+
+            return base.CanConvertTo(context, destinationType);
+        }
+
+        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
+        {
+            if (destinationType == typeof(String) && value is TabGradient)
+            {
+                return "DockPaneTabGradient";
+            }
+            return base.ConvertTo(context, culture, value, destinationType);
+        }
+    }
+    #endregion
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindow.SplitterControl.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindow.SplitterControl.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindow.SplitterControl.cs	(revision 2645)
@@ -0,0 +1,28 @@
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    public partial class DockWindow
+    {
+        private class SplitterControl : SplitterBase
+        {
+            protected override int SplitterSize
+            {
+                get { return Measures.SplitterSize; }
+            }
+
+            protected override void StartDrag()
+            {
+                DockWindow window = Parent as DockWindow;
+                if (window == null)
+                    return;
+
+                window.DockPanel.BeginDrag(window, window.RectangleToScreen(Bounds));
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindow.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindow.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindow.cs	(revision 2645)
@@ -0,0 +1,243 @@
+using System;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	[ToolboxItem(false)]
+	public partial class DockWindow : Panel, INestedPanesContainer, ISplitterDragSource
+	{
+		private DockPanel m_dockPanel;
+		private DockState m_dockState;
+		private SplitterControl m_splitter;
+		private NestedPaneCollection m_nestedPanes;
+
+		internal DockWindow(DockPanel dockPanel, DockState dockState)
+		{
+			m_nestedPanes = new NestedPaneCollection(this);
+			m_dockPanel = dockPanel;
+			m_dockState = dockState;
+			Visible = false;
+
+			SuspendLayout();
+
+			if (DockState == DockState.DockLeft || DockState == DockState.DockRight ||
+				DockState == DockState.DockTop || DockState == DockState.DockBottom)
+			{
+				m_splitter = new SplitterControl();
+				Controls.Add(m_splitter);
+			}
+
+			if (DockState == DockState.DockLeft)
+			{
+				Dock = DockStyle.Left;
+				m_splitter.Dock = DockStyle.Right;
+			}
+			else if (DockState == DockState.DockRight)
+			{
+				Dock = DockStyle.Right;
+				m_splitter.Dock = DockStyle.Left;
+			}
+			else if (DockState == DockState.DockTop)
+			{
+				Dock = DockStyle.Top;
+				m_splitter.Dock = DockStyle.Bottom;
+			}
+			else if (DockState == DockState.DockBottom)
+			{
+				Dock = DockStyle.Bottom;
+				m_splitter.Dock = DockStyle.Top;
+			}
+			else if (DockState == DockState.Document)
+			{
+				Dock = DockStyle.Fill;
+			}
+
+			ResumeLayout();
+		}
+
+		public VisibleNestedPaneCollection VisibleNestedPanes
+		{
+			get	{	return NestedPanes.VisibleNestedPanes;	}
+		}
+
+		public NestedPaneCollection NestedPanes
+		{
+			get	{	return m_nestedPanes;	}
+		}
+
+		public DockPanel DockPanel
+		{
+			get	{	return m_dockPanel;	}
+		}
+
+		public DockState DockState
+		{
+			get	{	return m_dockState;	}
+		}
+
+		public bool IsFloat
+		{
+			get	{	return DockState == DockState.Float;	}
+		}
+
+		internal DockPane DefaultPane
+		{
+			get	{	return VisibleNestedPanes.Count == 0 ? null : VisibleNestedPanes[0];	}
+		}
+
+		public virtual Rectangle DisplayingRectangle
+		{
+			get
+			{
+				Rectangle rect = ClientRectangle;
+				// if DockWindow is document, exclude the border
+				if (DockState == DockState.Document)
+				{
+					rect.X += 1;
+					rect.Y += 1;
+					rect.Width -= 2;
+					rect.Height -= 2;
+				}
+				// exclude the splitter
+				else if (DockState == DockState.DockLeft)
+					rect.Width -= Measures.SplitterSize;
+				else if (DockState == DockState.DockRight)
+				{
+					rect.X += Measures.SplitterSize;
+					rect.Width -= Measures.SplitterSize;
+				}
+				else if (DockState == DockState.DockTop)
+					rect.Height -= Measures.SplitterSize;
+				else if (DockState == DockState.DockBottom)
+				{
+					rect.Y += Measures.SplitterSize;
+					rect.Height -= Measures.SplitterSize;
+				}
+
+				return rect;
+			}
+		}
+
+		protected override void OnPaint(PaintEventArgs e)
+		{
+			// if DockWindow is document, draw the border
+            if (DockState == DockState.Document)
+                e.Graphics.DrawRectangle(SystemPens.ControlDark, ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
+
+			base.OnPaint(e);
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+			VisibleNestedPanes.Refresh();
+			if (VisibleNestedPanes.Count == 0)
+			{
+                if (Visible)
+                    Visible = false;
+			}
+			else if (!Visible)
+			{
+				Visible = true;
+				VisibleNestedPanes.Refresh();
+			}
+
+			base.OnLayout (levent);
+		}
+
+        #region ISplitterDragSource Members
+
+        void ISplitterDragSource.BeginDrag(Rectangle rectSplitter)
+        {
+        }
+
+        void ISplitterDragSource.EndDrag()
+        {
+        }
+
+        bool ISplitterDragSource.IsVertical
+        {
+            get { return (DockState == DockState.DockLeft || DockState == DockState.DockRight); }
+        }
+
+        Rectangle ISplitterDragSource.DragLimitBounds
+        {
+            get
+            {
+                Rectangle rectLimit = DockPanel.DockArea;
+                Point location;
+                if ((Control.ModifierKeys & Keys.Shift) == 0)
+                    location = Location;
+                else
+                    location = DockPanel.DockArea.Location;
+
+                if (((ISplitterDragSource)this).IsVertical)
+                {
+                    rectLimit.X += MeasurePane.MinSize;
+                    rectLimit.Width -= 2 * MeasurePane.MinSize;
+                    rectLimit.Y = location.Y;
+                    if ((Control.ModifierKeys & Keys.Shift) == 0)
+                        rectLimit.Height = Height;
+                }
+                else
+                {
+                    rectLimit.Y += MeasurePane.MinSize;
+                    rectLimit.Height -= 2 * MeasurePane.MinSize;
+                    rectLimit.X = location.X;
+                    if ((Control.ModifierKeys & Keys.Shift) == 0)
+                        rectLimit.Width = Width;
+                }
+
+                return DockPanel.RectangleToScreen(rectLimit);
+            }
+        }
+
+        void ISplitterDragSource.MoveSplitter(int offset)
+        {
+            if ((Control.ModifierKeys & Keys.Shift) != 0)
+                SendToBack();
+
+            Rectangle rectDockArea = DockPanel.DockArea;
+            if (DockState == DockState.DockLeft && rectDockArea.Width > 0)
+            {
+                if (DockPanel.DockLeftPortion > 1)
+                    DockPanel.DockLeftPortion = Width + offset;
+                else
+                    DockPanel.DockLeftPortion += ((double)offset) / (double)rectDockArea.Width;
+            }
+            else if (DockState == DockState.DockRight && rectDockArea.Width > 0)
+            {
+                if (DockPanel.DockRightPortion > 1)
+                    DockPanel.DockRightPortion = Width - offset;
+                else
+                    DockPanel.DockRightPortion -= ((double)offset) / (double)rectDockArea.Width;
+            }
+            else if (DockState == DockState.DockBottom && rectDockArea.Height > 0)
+            {
+                if (DockPanel.DockBottomPortion > 1)
+                    DockPanel.DockBottomPortion = Height - offset;
+                else
+                    DockPanel.DockBottomPortion -= ((double)offset) / (double)rectDockArea.Height;
+            }
+            else if (DockState == DockState.DockTop && rectDockArea.Height > 0)
+            {
+                if (DockPanel.DockTopPortion > 1)
+                    DockPanel.DockTopPortion = Height + offset;
+                else
+                    DockPanel.DockTopPortion += ((double)offset) / (double)rectDockArea.Height;
+            }
+        }
+
+        #region IDragSource Members
+
+        Control IDragSource.DragControl
+        {
+            get { return this; }
+        }
+
+        #endregion
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindowCollection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindowCollection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DockWindowCollection.cs	(revision 2645)
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public class DockWindowCollection : ReadOnlyCollection<DockWindow>
+	{
+		internal DockWindowCollection(DockPanel dockPanel)
+            : base(new List<DockWindow>())
+		{
+			Items.Add(new DockWindow(dockPanel, DockState.Document));
+			Items.Add(new DockWindow(dockPanel, DockState.DockLeft));
+			Items.Add(new DockWindow(dockPanel, DockState.DockRight));
+			Items.Add(new DockWindow(dockPanel, DockState.DockTop));
+			Items.Add(new DockWindow(dockPanel, DockState.DockBottom));
+		}
+
+		public DockWindow this [DockState dockState]
+		{
+			get
+			{
+				if (dockState == DockState.Document)
+					return Items[0];
+				else if (dockState == DockState.DockLeft || dockState == DockState.DockLeftAutoHide)
+					return Items[1];
+				else if (dockState == DockState.DockRight || dockState == DockState.DockRightAutoHide)
+					return Items[2];
+				else if (dockState == DockState.DockTop || dockState == DockState.DockTopAutoHide)
+					return Items[3];
+				else if (dockState == DockState.DockBottom || dockState == DockState.DockBottomAutoHide)
+					return Items[4];
+
+				throw (new ArgumentOutOfRangeException());
+			}
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DragForm.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DragForm.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DragForm.cs	(revision 2645)
@@ -0,0 +1,64 @@
+using System;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	// Inspired by Chris Sano's article:
+	// http://msdn.microsoft.com/smartclient/default.aspx?pull=/library/en-us/dnwinforms/html/colorpicker.asp
+	// In Sano's article, the DragForm needs to meet the following criteria:
+	// (1) it was not to show up in the task bar;
+	//     ShowInTaskBar = false
+	// (2) it needed to be the top-most window;
+	//     TopMost = true (not necessary here)
+	// (3) its icon could not show up in the ALT+TAB window if the user pressed ALT+TAB during a drag-and-drop;
+	//     FormBorderStyle = FormBorderStyle.None;
+	//     Create with WS_EX_TOOLWINDOW window style.
+	//     Compares with the solution in the artile by setting FormBorderStyle as FixedToolWindow,
+	//     and then clip the window caption and border, this way is much simplier.
+	// (4) it was not to steal focus from the application when displayed.
+	//     User Win32 ShowWindow API with SW_SHOWNOACTIVATE
+	// In addition, this form should only for display and therefore should act as transparent, otherwise
+	// WindowFromPoint will return this form, instead of the control beneath. Need BOTH of the following to
+	// achieve this (don't know why, spent hours to try it out :( ):
+	//  1. Enabled = false;
+	//  2. WM_NCHITTEST returns HTTRANSPARENT
+	internal class DragForm : Form
+	{
+		public DragForm()
+		{
+			FormBorderStyle = FormBorderStyle.None;
+			ShowInTaskbar = false;
+			SetStyle(ControlStyles.Selectable, false);
+			Enabled = false;
+		}
+
+		protected override CreateParams CreateParams
+		{
+			get
+			{
+				CreateParams createParams = base.CreateParams;
+				createParams.ExStyle |= (int)Win32.WindowExStyles.WS_EX_TOOLWINDOW;
+				return createParams;
+			}
+		}
+
+		protected override void WndProc(ref Message m)
+		{
+			if (m.Msg == (int)Win32.Msgs.WM_NCHITTEST)
+			{
+				m.Result = (IntPtr)Win32.HitTest.HTTRANSPARENT;
+				return;
+			}
+
+			base.WndProc (ref m);
+		}
+
+		public virtual void Show(bool bActivate)
+		{
+			if (bActivate)
+				Show();
+			else
+				NativeMethods.ShowWindow(Handle, (int)Win32.ShowWindowStyles.SW_SHOWNOACTIVATE);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DummyControl.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DummyControl.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/DummyControl.cs	(revision 2645)
@@ -0,0 +1,13 @@
+using System;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal class DummyControl : Control
+	{
+		public DummyControl()
+		{
+			SetStyle(ControlStyles.Selectable, false);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Enums.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Enums.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Enums.cs	(revision 2645)
@@ -0,0 +1,60 @@
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	[Flags]
+	[Serializable]
+	[Editor(typeof(DockAreasEditor), typeof(System.Drawing.Design.UITypeEditor))]
+	public enum DockAreas
+	{
+		Float = 1,
+		DockLeft = 2,
+		DockRight = 4,
+		DockTop = 8,
+		DockBottom = 16,
+		Document = 32
+	}
+
+	public enum DockState
+	{
+		Unknown = 0,
+		Float = 1,
+		DockTopAutoHide = 2,
+		DockLeftAutoHide = 3,
+		DockBottomAutoHide = 4,
+		DockRightAutoHide = 5,
+		Document = 6,
+		DockTop = 7,
+		DockLeft = 8,
+		DockBottom = 9,
+		DockRight = 10,
+		Hidden = 11
+	}
+
+	public enum DockAlignment
+	{
+		Left,
+		Right,
+		Top,
+		Bottom
+	}
+
+	public enum DocumentStyle
+	{
+		DockingMdi,
+		DockingWindow,
+		DockingSdi,
+		SystemMdi,
+	}
+
+    /// <summary>
+    /// The location to draw the DockPaneStrip for Document style windows.
+    /// </summary>
+    public enum DocumentTabStripLocation
+    {
+        Top,
+        Bottom
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/FloatWindow.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/FloatWindow.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/FloatWindow.cs	(revision 2645)
@@ -0,0 +1,453 @@
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
+using System.Diagnostics.CodeAnalysis;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public class FloatWindow : Form, INestedPanesContainer, IDockDragSource
+	{
+		private NestedPaneCollection m_nestedPanes;
+		internal const int WM_CHECKDISPOSE = (int)(Win32.Msgs.WM_USER + 1);
+
+		internal protected FloatWindow(DockPanel dockPanel, DockPane pane)
+		{
+			InternalConstruct(dockPanel, pane, false, Rectangle.Empty);
+		}
+
+		internal protected FloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
+		{
+			InternalConstruct(dockPanel, pane, true, bounds);
+		}
+
+		private void InternalConstruct(DockPanel dockPanel, DockPane pane, bool boundsSpecified, Rectangle bounds)
+		{
+			if (dockPanel == null)
+				throw(new ArgumentNullException(Strings.FloatWindow_Constructor_NullDockPanel));
+
+			m_nestedPanes = new NestedPaneCollection(this);
+
+			FormBorderStyle = FormBorderStyle.SizableToolWindow;
+			ShowInTaskbar = false;
+            if (dockPanel.RightToLeft != RightToLeft)
+                RightToLeft = dockPanel.RightToLeft;
+            if (RightToLeftLayout != dockPanel.RightToLeftLayout)
+                RightToLeftLayout = dockPanel.RightToLeftLayout;
+			
+			SuspendLayout();
+            if (boundsSpecified)
+            {
+                Bounds = bounds;
+                StartPosition = FormStartPosition.Manual;
+            }
+            else
+            {
+                StartPosition = FormStartPosition.WindowsDefaultLocation;
+                Size = dockPanel.DefaultFloatWindowSize;
+            }
+
+			m_dockPanel = dockPanel;
+			Owner = DockPanel.FindForm();
+			DockPanel.AddFloatWindow(this);
+			if (pane != null)
+				pane.FloatWindow = this;
+
+			ResumeLayout();
+		}
+
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing)
+			{
+				if (DockPanel != null)
+					DockPanel.RemoveFloatWindow(this);
+				m_dockPanel = null;
+			}
+			base.Dispose(disposing);
+		}
+
+		private bool m_allowEndUserDocking = true;
+		public bool AllowEndUserDocking
+		{
+			get	{	return m_allowEndUserDocking;	}
+			set	{	m_allowEndUserDocking = value;	}
+		}
+
+		public NestedPaneCollection NestedPanes
+		{
+			get	{	return m_nestedPanes;	}
+		}
+
+		public VisibleNestedPaneCollection VisibleNestedPanes
+		{
+			get	{	return NestedPanes.VisibleNestedPanes;	}
+		}
+
+		private DockPanel m_dockPanel;
+		public DockPanel DockPanel
+		{
+			get	{	return m_dockPanel;	}
+		}
+
+		public DockState DockState
+		{
+			get	{	return DockState.Float;	}
+		}
+	
+		public bool IsFloat
+		{
+			get	{	return DockState == DockState.Float;	}
+		}
+
+		internal bool IsDockStateValid(DockState dockState)
+		{
+			foreach (DockPane pane in NestedPanes)
+				foreach (IDockContent content in pane.Contents)
+					if (!DockHelper.IsDockStateValid(dockState, content.DockHandler.DockAreas))
+						return false;
+
+			return true;
+		}
+
+		protected override void OnActivated(EventArgs e)
+		{
+			DockPanel.FloatWindows.BringWindowToFront(this);
+			base.OnActivated (e);
+			// Propagate the Activated event to the visible panes content objects
+			foreach (DockPane pane in VisibleNestedPanes)
+				foreach (IDockContent content in pane.Contents)
+					content.OnActivated(e);
+		}
+
+		protected override void OnDeactivate(EventArgs e)
+		{
+			base.OnDeactivate(e);
+			// Propagate the Deactivate event to the visible panes content objects
+			foreach (DockPane pane in VisibleNestedPanes)
+				foreach (IDockContent content in pane.Contents)
+					content.OnDeactivate(e);
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+			VisibleNestedPanes.Refresh();
+			RefreshChanges();
+            Visible = (VisibleNestedPanes.Count > 0);
+            SetText();
+
+			base.OnLayout(levent);
+		}
+
+
+        [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.Windows.Forms.Control.set_Text(System.String)")]
+        internal void SetText()
+		{
+			DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null;
+
+			if (theOnlyPane == null)
+				Text = " ";	// use " " instead of string.Empty because the whole title bar will disappear when ControlBox is set to false.
+			else if (theOnlyPane.ActiveContent == null)
+				Text = " ";
+			else
+				Text = theOnlyPane.ActiveContent.DockHandler.TabText;
+		}
+
+		protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
+		{
+			Rectangle rectWorkArea = SystemInformation.VirtualScreen;
+
+			if (y + height > rectWorkArea.Bottom)
+				y -= (y + height) - rectWorkArea.Bottom;
+
+			if (y < rectWorkArea.Top)
+				y += rectWorkArea.Top - y;
+
+			base.SetBoundsCore (x, y, width, height, specified);
+		}
+
+        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
+		protected override void WndProc(ref Message m)
+		{
+			if (m.Msg == (int)Win32.Msgs.WM_NCLBUTTONDOWN)
+			{
+				if (IsDisposed)
+					return;
+
+				uint result = NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
+				if (result == 2 && DockPanel.AllowEndUserDocking && this.AllowEndUserDocking)	// HITTEST_CAPTION
+				{
+					Activate();
+					m_dockPanel.BeginDrag(this);
+				}
+				else
+					base.WndProc(ref m);
+
+				return;
+			}
+            else if (m.Msg == (int)Win32.Msgs.WM_NCRBUTTONDOWN)
+            {
+                uint result = NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
+                if (result == 2)	// HITTEST_CAPTION
+                {
+                    DockPane theOnlyPane = (VisibleNestedPanes.Count == 1) ? VisibleNestedPanes[0] : null;
+                    if (theOnlyPane != null && theOnlyPane.ActiveContent != null)
+                    {
+                        theOnlyPane.ShowTabPageContextMenu(this, PointToClient(Control.MousePosition));
+                        return;
+                    }
+                }
+
+                base.WndProc(ref m);
+                return;
+            }
+            else if (m.Msg == (int)Win32.Msgs.WM_CLOSE)
+            {
+                if (NestedPanes.Count == 0)
+                {
+                    base.WndProc(ref m);
+                    return;
+                }
+
+                for (int i = NestedPanes.Count - 1; i >= 0; i--)
+                {
+                    DockContentCollection contents = NestedPanes[i].Contents;
+                    for (int j = contents.Count - 1; j >= 0; j--)
+                    {
+                        IDockContent content = contents[j];
+                        if (content.DockHandler.DockState != DockState.Float)
+                            continue;
+
+                        if (!content.DockHandler.CloseButton)
+                            continue;
+
+                        if (content.DockHandler.HideOnClose)
+                            content.DockHandler.Hide();
+                        else
+                            content.DockHandler.Close();
+                    }
+                }
+
+                return;
+            }
+            else if (m.Msg == (int)Win32.Msgs.WM_NCLBUTTONDBLCLK)
+            {
+                uint result = NativeMethods.SendMessage(this.Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, (uint)m.LParam);
+                if (result != 2)	// HITTEST_CAPTION
+                {
+                    base.WndProc(ref m);
+                    return;
+                }
+
+                DockPanel.SuspendLayout(true);
+
+                // Restore to panel
+                foreach (DockPane pane in NestedPanes)
+                {
+                    if (pane.DockState != DockState.Float)
+                        continue;
+                    pane.RestoreToPanel();
+                }
+
+
+                DockPanel.ResumeLayout(true, true);
+                return;
+            }
+            else if (m.Msg == WM_CHECKDISPOSE)
+            {
+                if (NestedPanes.Count == 0)
+                    Dispose();
+
+                return;
+            }
+
+			base.WndProc(ref m);
+		}
+
+		internal void RefreshChanges()
+		{
+            if (IsDisposed)
+                return;
+
+			if (VisibleNestedPanes.Count == 0)
+			{
+				ControlBox = true;
+				return;
+			}
+
+			for (int i=VisibleNestedPanes.Count - 1; i>=0; i--)
+			{
+				DockContentCollection contents = VisibleNestedPanes[i].Contents;
+				for (int j=contents.Count - 1; j>=0; j--)
+				{
+					IDockContent content = contents[j];
+					if (content.DockHandler.DockState != DockState.Float)
+						continue;
+
+					if (content.DockHandler.CloseButton && content.DockHandler.CloseButtonVisible)
+					{
+						ControlBox = true;
+						return;
+					}
+				}
+			}
+			//Only if there is a ControlBox do we turn it off
+			//old code caused a flash of the window.
+            if (ControlBox)
+				ControlBox = false;
+		}
+
+		public virtual Rectangle DisplayingRectangle
+		{
+			get	{	return ClientRectangle;	}
+		}
+
+		internal void TestDrop(IDockDragSource dragSource, DockOutlineBase dockOutline)
+		{
+            if (VisibleNestedPanes.Count == 1)
+            {
+                DockPane pane = VisibleNestedPanes[0];
+                if (!dragSource.CanDockTo(pane))
+                    return;
+
+                Point ptMouse = Control.MousePosition;
+                uint lParam = Win32Helper.MakeLong(ptMouse.X, ptMouse.Y);
+                if (NativeMethods.SendMessage(Handle, (int)Win32.Msgs.WM_NCHITTEST, 0, lParam) == (uint)Win32.HitTest.HTCAPTION)
+                    dockOutline.Show(VisibleNestedPanes[0], -1);
+            }
+		}
+
+        #region IDockDragSource Members
+
+        #region IDragSource Members
+
+        Control IDragSource.DragControl
+        {
+            get { return this; }
+        }
+
+        #endregion
+
+        bool IDockDragSource.IsDockStateValid(DockState dockState)
+        {
+            return IsDockStateValid(dockState);
+        }
+
+        bool IDockDragSource.CanDockTo(DockPane pane)
+        {
+            if (!IsDockStateValid(pane.DockState))
+                return false;
+
+            if (pane.FloatWindow == this)
+                return false;
+
+            return true;
+        }
+
+        Rectangle IDockDragSource.BeginDrag(Point ptMouse)
+        {
+            return Bounds;
+        }
+
+        public  void FloatAt(Rectangle floatWindowBounds)
+        {
+            Bounds = floatWindowBounds;
+        }
+
+        public void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex)
+        {
+            if (dockStyle == DockStyle.Fill)
+            {
+                for (int i = NestedPanes.Count - 1; i >= 0; i--)
+                {
+                    DockPane paneFrom = NestedPanes[i];
+                    for (int j = paneFrom.Contents.Count - 1; j >= 0; j--)
+                    {
+                        IDockContent c = paneFrom.Contents[j];
+                        c.DockHandler.Pane = pane;
+                        if (contentIndex != -1)
+                            pane.SetContentIndex(c, contentIndex);
+                        c.DockHandler.Activate();
+                    }
+                }
+            }
+            else
+            {
+                DockAlignment alignment = DockAlignment.Left;
+                if (dockStyle == DockStyle.Left)
+                    alignment = DockAlignment.Left;
+                else if (dockStyle == DockStyle.Right)
+                    alignment = DockAlignment.Right;
+                else if (dockStyle == DockStyle.Top)
+                    alignment = DockAlignment.Top;
+                else if (dockStyle == DockStyle.Bottom)
+                    alignment = DockAlignment.Bottom;
+
+                MergeNestedPanes(VisibleNestedPanes, pane.NestedPanesContainer.NestedPanes, pane, alignment, 0.5);
+            }
+        }
+
+        public void DockTo(DockPanel panel, DockStyle dockStyle)
+        {
+            if (panel != DockPanel)
+                throw new ArgumentException(Strings.IDockDragSource_DockTo_InvalidPanel, "panel");
+
+            NestedPaneCollection nestedPanesTo = null;
+
+            if (dockStyle == DockStyle.Top)
+                nestedPanesTo = DockPanel.DockWindows[DockState.DockTop].NestedPanes;
+            else if (dockStyle == DockStyle.Bottom)
+                nestedPanesTo = DockPanel.DockWindows[DockState.DockBottom].NestedPanes;
+            else if (dockStyle == DockStyle.Left)
+                nestedPanesTo = DockPanel.DockWindows[DockState.DockLeft].NestedPanes;
+            else if (dockStyle == DockStyle.Right)
+                nestedPanesTo = DockPanel.DockWindows[DockState.DockRight].NestedPanes;
+            else if (dockStyle == DockStyle.Fill)
+                nestedPanesTo = DockPanel.DockWindows[DockState.Document].NestedPanes;
+
+            DockPane prevPane = null;
+            for (int i = nestedPanesTo.Count - 1; i >= 0; i--)
+                if (nestedPanesTo[i] != VisibleNestedPanes[0])
+                    prevPane = nestedPanesTo[i];
+            MergeNestedPanes(VisibleNestedPanes, nestedPanesTo, prevPane, DockAlignment.Left, 0.5);
+        }
+
+        private static void MergeNestedPanes(VisibleNestedPaneCollection nestedPanesFrom, NestedPaneCollection nestedPanesTo, DockPane prevPane, DockAlignment alignment, double proportion)
+        {
+            if (nestedPanesFrom.Count == 0)
+                return;
+
+            int count = nestedPanesFrom.Count;
+            DockPane[] panes = new DockPane[count];
+            DockPane[] prevPanes = new DockPane[count];
+            DockAlignment[] alignments = new DockAlignment[count];
+            double[] proportions = new double[count];
+
+            for (int i = 0; i < count; i++)
+            {
+                panes[i] = nestedPanesFrom[i];
+                prevPanes[i] = nestedPanesFrom[i].NestedDockingStatus.PreviousPane;
+                alignments[i] = nestedPanesFrom[i].NestedDockingStatus.Alignment;
+                proportions[i] = nestedPanesFrom[i].NestedDockingStatus.Proportion;
+            }
+
+            DockPane pane = panes[0].DockTo(nestedPanesTo.Container, prevPane, alignment, proportion);
+            panes[0].DockState = nestedPanesTo.DockState;
+
+            for (int i = 1; i < count; i++)
+            {
+                for (int j = i; j < count; j++)
+                {
+                    if (prevPanes[j] == panes[i - 1])
+                        prevPanes[j] = pane;
+                }
+                pane = panes[i].DockTo(nestedPanesTo.Container, prevPanes[i], alignments[i], proportions[i]);
+                panes[i].DockState = nestedPanesTo.DockState;
+            }
+        }
+
+        #endregion
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/FloatWindowCollection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/FloatWindowCollection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/FloatWindowCollection.cs	(revision 2645)
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public class FloatWindowCollection : ReadOnlyCollection<FloatWindow>
+	{
+		internal FloatWindowCollection()
+            : base(new List<FloatWindow>())
+		{
+		}
+
+		internal int Add(FloatWindow fw)
+		{
+			if (Items.Contains(fw))
+				return Items.IndexOf(fw);
+
+			Items.Add(fw);
+            return Count - 1;
+		}
+
+		internal void Dispose()
+		{
+			for (int i=Count - 1; i>=0; i--)
+				this[i].Close();
+		}
+
+		internal void Remove(FloatWindow fw)
+		{
+			Items.Remove(fw);
+		}
+
+		internal void BringWindowToFront(FloatWindow fw)
+		{
+			Items.Remove(fw);
+			Items.Add(fw);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/DockHelper.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/DockHelper.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/DockHelper.cs	(revision 2645)
@@ -0,0 +1,103 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal static class DockHelper
+	{
+		public static bool IsDockStateAutoHide(DockState dockState)
+		{
+			if (dockState == DockState.DockLeftAutoHide ||
+				dockState == DockState.DockRightAutoHide ||
+				dockState == DockState.DockTopAutoHide ||
+				dockState == DockState.DockBottomAutoHide)
+				return true;
+			else
+				return false;
+		}
+
+		public static bool IsDockStateValid(DockState dockState, DockAreas dockableAreas)
+		{
+			if (((dockableAreas & DockAreas.Float) == 0) &&
+				(dockState == DockState.Float))
+				return false;
+			else if (((dockableAreas & DockAreas.Document) == 0) &&
+				(dockState == DockState.Document))
+				return false;
+			else if (((dockableAreas & DockAreas.DockLeft) == 0) &&
+				(dockState == DockState.DockLeft || dockState == DockState.DockLeftAutoHide))
+				return false;
+			else if (((dockableAreas & DockAreas.DockRight) == 0) &&
+				(dockState == DockState.DockRight || dockState == DockState.DockRightAutoHide))
+				return false;
+			else if (((dockableAreas & DockAreas.DockTop) == 0) &&
+				(dockState == DockState.DockTop || dockState == DockState.DockTopAutoHide))
+				return false;
+			else if (((dockableAreas & DockAreas.DockBottom) == 0) &&
+				(dockState == DockState.DockBottom || dockState == DockState.DockBottomAutoHide))
+				return false;
+			else
+				return true;
+		}
+
+		public static bool IsDockWindowState(DockState state)
+		{
+			if (state == DockState.DockTop || state == DockState.DockBottom || state == DockState.DockLeft ||
+				state == DockState.DockRight || state == DockState.Document)
+				return true;
+			else
+				return false;
+		}
+
+		public static DockState ToggleAutoHideState(DockState state)
+		{
+			if (state == DockState.DockLeft)
+				return DockState.DockLeftAutoHide;
+			else if (state == DockState.DockRight)
+				return DockState.DockRightAutoHide;
+			else if (state == DockState.DockTop)
+				return DockState.DockTopAutoHide;
+			else if (state == DockState.DockBottom)
+				return DockState.DockBottomAutoHide;
+			else if (state == DockState.DockLeftAutoHide)
+				return DockState.DockLeft;
+			else if (state == DockState.DockRightAutoHide)
+				return DockState.DockRight;
+			else if (state == DockState.DockTopAutoHide)
+				return DockState.DockTop;
+			else if (state == DockState.DockBottomAutoHide)
+				return DockState.DockBottom;
+			else
+				return state;
+		}
+
+		public static DockPane PaneAtPoint(Point pt, DockPanel dockPanel)
+		{
+			for (Control control = Win32Helper.ControlAtPoint(pt); control != null; control = control.Parent)
+			{
+				IDockContent content = control as IDockContent;
+				if (content != null && content.DockHandler.DockPanel == dockPanel)
+					return content.DockHandler.Pane;
+
+				DockPane pane = control as DockPane;
+				if (pane != null && pane.DockPanel == dockPanel)
+					return pane;
+			}
+
+			return null;
+		}
+
+		public static FloatWindow FloatWindowAtPoint(Point pt, DockPanel dockPanel)
+		{
+			for (Control control = Win32Helper.ControlAtPoint(pt); control != null; control = control.Parent)
+			{
+				FloatWindow floatWindow = control as FloatWindow;
+				if (floatWindow != null && floatWindow.DockPanel == dockPanel)
+					return floatWindow;
+			}
+
+			return null;
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/DrawHelper.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/DrawHelper.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/DrawHelper.cs	(revision 2645)
@@ -0,0 +1,88 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Imaging;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal static class DrawHelper
+	{
+        public static Point RtlTransform(Control control, Point point)
+        {
+            if (control.RightToLeft != RightToLeft.Yes)
+                return point;
+            else
+                return new Point(control.Right - point.X, point.Y);
+        }
+
+        public static Rectangle RtlTransform(Control control, Rectangle rectangle)
+        {
+            if (control.RightToLeft != RightToLeft.Yes)
+                return rectangle;
+            else
+                return new Rectangle(control.ClientRectangle.Right - rectangle.Right, rectangle.Y, rectangle.Width, rectangle.Height);
+        }
+
+        public static GraphicsPath GetRoundedCornerTab(GraphicsPath graphicsPath, Rectangle rect, bool upCorner)
+        {
+            if (graphicsPath == null)
+                graphicsPath = new GraphicsPath();
+            else
+                graphicsPath.Reset();
+            
+            int curveSize = 6;
+            if (upCorner)
+            {
+                graphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Top + curveSize / 2);
+                graphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90);
+                graphicsPath.AddLine(rect.Left + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top);
+                graphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90);
+                graphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom);
+            }
+            else
+            {
+                graphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Bottom - curveSize / 2);
+                graphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom - curveSize, curveSize, curveSize), 0, 90);
+                graphicsPath.AddLine(rect.Right - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom);
+                graphicsPath.AddArc(new Rectangle(rect.Left, rect.Bottom - curveSize, curveSize, curveSize), 90, 90);
+                graphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top);
+            }
+
+            return graphicsPath;
+        }
+
+		public static GraphicsPath CalculateGraphicsPathFromBitmap(Bitmap bitmap)
+		{
+			return CalculateGraphicsPathFromBitmap(bitmap, Color.Empty);
+		}
+
+		// From http://edu.cnzz.cn/show_3281.html
+		public static GraphicsPath CalculateGraphicsPathFromBitmap(Bitmap bitmap, Color colorTransparent) 
+		{ 
+			GraphicsPath graphicsPath = new GraphicsPath(); 
+			if (colorTransparent == Color.Empty)
+				colorTransparent = bitmap.GetPixel(0, 0); 
+
+			for(int row = 0; row < bitmap.Height; row ++) 
+			{ 
+				int colOpaquePixel = 0;
+				for(int col = 0; col < bitmap.Width; col ++) 
+				{ 
+					if(bitmap.GetPixel(col, row) != colorTransparent) 
+					{ 
+						colOpaquePixel = col; 
+						int colNext = col; 
+						for(colNext = colOpaquePixel; colNext < bitmap.Width; colNext ++) 
+							if(bitmap.GetPixel(colNext, row) == colorTransparent) 
+								break;
+ 
+						graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1)); 
+						col = colNext; 
+					} 
+				} 
+			} 
+			return graphicsPath; 
+		} 
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/ResourceHelper.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/ResourceHelper.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/ResourceHelper.cs	(revision 2645)
@@ -0,0 +1,29 @@
+using System;
+using System.Drawing;
+using System.Reflection;
+using System.Resources;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal static class ResourceHelper
+	{
+        private static ResourceManager _resourceManager = null;
+
+        private static ResourceManager ResourceManager
+        {
+            get
+            {
+                if (_resourceManager == null)
+                    _resourceManager = new ResourceManager("WeifenLuo.WinFormsUI.Docking.Strings", typeof(ResourceHelper).Assembly);
+                return _resourceManager;
+            }
+
+        }
+
+		public static string GetString(string name)
+		{
+			return ResourceManager.GetString(name);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/Win32Helper.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/Win32Helper.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Helpers/Win32Helper.cs	(revision 2645)
@@ -0,0 +1,19 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal static class Win32Helper
+	{
+		public static Control ControlAtPoint(Point pt)
+		{
+			return Control.FromChildHandle(NativeMethods.WindowFromPoint(pt));
+		}
+
+		public static uint MakeLong(int low, int high)
+		{
+			return (uint)((high << 16) + low);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/InertButtonBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/InertButtonBase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/InertButtonBase.cs	(revision 2645)
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Drawing.Imaging;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    internal abstract class InertButtonBase : Control
+    {
+        protected InertButtonBase()
+        {
+            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+            BackColor = Color.Transparent;
+        }
+
+        public abstract Bitmap Image
+        {
+            get;
+        }
+
+        private bool m_isMouseOver = false;
+        protected bool IsMouseOver
+        {
+            get { return m_isMouseOver; }
+            private set
+            {
+                if (m_isMouseOver == value)
+                    return;
+
+                m_isMouseOver = value;
+                Invalidate();
+            }
+        }
+
+        protected override Size DefaultSize
+        {
+            get { return Resources.DockPane_Close.Size; }
+        }
+
+        protected override void OnMouseMove(MouseEventArgs e)
+        {
+            base.OnMouseMove(e);
+            bool over = ClientRectangle.Contains(e.X, e.Y);
+            if (IsMouseOver != over)
+                IsMouseOver = over;
+        }
+
+        protected override void OnMouseEnter(EventArgs e)
+        {
+            base.OnMouseEnter(e);
+            if (!IsMouseOver)
+                IsMouseOver = true;
+        }
+
+        protected override void OnMouseLeave(EventArgs e)
+        {
+            base.OnMouseLeave(e);
+            if (IsMouseOver)
+                IsMouseOver = false;
+        }
+
+        protected override void OnPaint(PaintEventArgs e)
+        {
+            if (IsMouseOver && Enabled)
+            {
+                using (Pen pen = new Pen(ForeColor))
+                {
+                    e.Graphics.DrawRectangle(pen, Rectangle.Inflate(ClientRectangle, -1, -1));
+                }
+            }
+
+            using (ImageAttributes imageAttributes = new ImageAttributes())
+            {
+                ColorMap[] colorMap = new ColorMap[2];
+                colorMap[0] = new ColorMap();
+                colorMap[0].OldColor = Color.FromArgb(0, 0, 0);
+                colorMap[0].NewColor = ForeColor;
+                colorMap[1] = new ColorMap();
+                colorMap[1].OldColor = Image.GetPixel(0, 0);
+                colorMap[1].NewColor = Color.Transparent;
+
+                imageAttributes.SetRemapTable(colorMap);
+
+                e.Graphics.DrawImage(
+                   Image,
+                   new Rectangle(0, 0, Image.Width, Image.Height),
+                   0, 0,
+                   Image.Width,
+                   Image.Height,
+                   GraphicsUnit.Pixel,
+                   imageAttributes);
+            }
+
+            base.OnPaint(e);
+        }
+
+        public void RefreshChanges()
+        {
+            if (IsDisposed)
+                return;
+
+            bool mouseOver = ClientRectangle.Contains(PointToClient(Control.MousePosition));
+            if (mouseOver != IsMouseOver)
+                IsMouseOver = mouseOver;
+
+            OnRefreshChanges();
+        }
+
+        protected virtual void OnRefreshChanges()
+        {
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Interfaces.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Interfaces.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Interfaces.cs	(revision 2645)
@@ -0,0 +1,46 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public interface IDockContent
+	{
+		DockContentHandler DockHandler	{	get;	}
+		void OnActivated(EventArgs e);
+		void OnDeactivate(EventArgs e);
+	}
+
+	public interface INestedPanesContainer
+	{
+		DockState DockState	{	get;	}
+		Rectangle DisplayingRectangle	{	get;	}
+		NestedPaneCollection NestedPanes	{	get;	}
+		VisibleNestedPaneCollection VisibleNestedPanes	{	get;	}
+		bool IsFloat	{	get;	}
+	}
+
+    internal interface IDragSource
+    {
+        Control DragControl { get; }
+    }
+
+    internal interface IDockDragSource : IDragSource
+    {
+        Rectangle BeginDrag(Point ptMouse);
+        bool IsDockStateValid(DockState dockState);
+        bool CanDockTo(DockPane pane);
+        void FloatAt(Rectangle floatWindowBounds);
+        void DockTo(DockPane pane, DockStyle dockStyle, int contentIndex);
+        void DockTo(DockPanel panel, DockStyle dockStyle);
+    }
+
+    internal interface ISplitterDragSource : IDragSource
+    {
+        void BeginDrag(Rectangle rectSplitter);
+        void EndDrag();
+        bool IsVertical { get; }
+        Rectangle DragLimitBounds { get; }
+        void MoveSplitter(int offset);
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Localization.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Localization.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Localization.cs	(revision 2645)
@@ -0,0 +1,46 @@
+using System;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	[AttributeUsage(AttributeTargets.All)]
+	internal sealed class LocalizedDescriptionAttribute : DescriptionAttribute
+	{
+		private bool m_initialized = false;
+
+		public LocalizedDescriptionAttribute(string key) : base(key)
+		{
+		}
+
+		public override string Description
+		{
+			get
+			{	
+				if (!m_initialized)
+				{
+					string key = base.Description;
+					DescriptionValue = ResourceHelper.GetString(key);
+					if (DescriptionValue == null)
+						DescriptionValue = String.Empty;
+
+					m_initialized = true;
+				}
+
+				return DescriptionValue;
+			}
+		}
+	}
+
+	[AttributeUsage(AttributeTargets.All)]
+	internal sealed class LocalizedCategoryAttribute : CategoryAttribute
+	{
+		public LocalizedCategoryAttribute(string key) : base(key)
+		{
+		}
+
+		protected override string GetLocalizedString(string key)
+		{
+			return ResourceHelper.GetString(key);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Measures.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Measures.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Measures.cs	(revision 2645)
@@ -0,0 +1,14 @@
+using System;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal static class Measures
+	{
+		public const int SplitterSize = 4;
+	}
+
+	internal static class MeasurePane
+	{
+		public const int MinSize = 24;
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/NestedDockingStatus.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/NestedDockingStatus.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/NestedDockingStatus.cs	(revision 2645)
@@ -0,0 +1,108 @@
+using System;
+using System.Drawing;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public sealed class NestedDockingStatus
+	{
+		internal NestedDockingStatus(DockPane pane)
+		{
+			m_dockPane = pane;
+		}
+
+		private DockPane m_dockPane = null;
+		public DockPane DockPane
+		{
+			get	{	return m_dockPane;	}
+		}
+		
+		private NestedPaneCollection m_nestedPanes = null;
+		public NestedPaneCollection NestedPanes
+		{
+			get	{	return m_nestedPanes;	}
+		}
+		
+		private DockPane m_previousPane = null;
+		public DockPane PreviousPane
+		{
+			get	{	return m_previousPane;	}
+		}
+
+		private DockAlignment m_alignment = DockAlignment.Left;
+		public DockAlignment Alignment
+		{
+			get	{	return m_alignment;	}
+		}
+
+		private double m_proportion = 0.5;
+		public double Proportion
+		{
+			get	{	return m_proportion;	}
+		}
+
+		private bool m_isDisplaying = false;
+		public bool IsDisplaying
+		{
+			get	{	return m_isDisplaying;	}
+		}
+
+		private DockPane m_displayingPreviousPane = null;
+		public DockPane DisplayingPreviousPane
+		{
+			get	{	return m_displayingPreviousPane;	}
+		}
+
+		private DockAlignment m_displayingAlignment = DockAlignment.Left;
+		public DockAlignment DisplayingAlignment
+		{
+			get	{	return m_displayingAlignment;	}
+		}
+
+		private double m_displayingProportion = 0.5;
+		public double DisplayingProportion
+		{
+			get	{	return m_displayingProportion;	}
+		}
+
+		private Rectangle m_logicalBounds = Rectangle.Empty; 
+		public Rectangle LogicalBounds
+		{
+			get	{	return m_logicalBounds;	}
+		}
+
+		private Rectangle m_paneBounds = Rectangle.Empty;
+		public Rectangle PaneBounds
+		{
+			get	{	return m_paneBounds;	}
+		}
+
+		private Rectangle m_splitterBounds = Rectangle.Empty;
+		public Rectangle SplitterBounds
+		{
+			get	{	return m_splitterBounds;	}
+		}
+
+		internal void SetStatus(NestedPaneCollection nestedPanes, DockPane previousPane, DockAlignment alignment, double proportion)
+		{
+			m_nestedPanes = nestedPanes;
+			m_previousPane = previousPane;
+			m_alignment = alignment;
+			m_proportion = proportion;
+		}
+
+		internal void SetDisplayingStatus(bool isDisplaying, DockPane displayingPreviousPane, DockAlignment displayingAlignment, double displayingProportion)
+		{
+			m_isDisplaying = isDisplaying;
+			m_displayingPreviousPane = displayingPreviousPane;
+			m_displayingAlignment = displayingAlignment;
+			m_displayingProportion = displayingProportion;
+		}
+
+		internal void SetDisplayingBounds(Rectangle logicalBounds, Rectangle paneBounds, Rectangle splitterBounds)
+		{
+			m_logicalBounds = logicalBounds;
+			m_paneBounds = paneBounds;
+			m_splitterBounds = splitterBounds;
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/NestedPaneCollection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/NestedPaneCollection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/NestedPaneCollection.cs	(revision 2645)
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Drawing;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public sealed class NestedPaneCollection : ReadOnlyCollection<DockPane>
+	{
+		private INestedPanesContainer m_container;
+		private VisibleNestedPaneCollection m_visibleNestedPanes;
+
+		internal NestedPaneCollection(INestedPanesContainer container)
+            : base(new List<DockPane>())
+		{
+			m_container = container;
+			m_visibleNestedPanes = new VisibleNestedPaneCollection(this);
+		}
+
+		public INestedPanesContainer Container
+		{
+			get	{	return m_container;	}
+		}
+		
+		public VisibleNestedPaneCollection VisibleNestedPanes
+		{
+			get	{	return m_visibleNestedPanes;	}
+		}
+
+		public DockState DockState
+		{
+			get	{	return Container.DockState;	}
+		}
+
+		public bool IsFloat
+		{
+			get	{	return DockState == DockState.Float;	}
+		}
+
+		internal void Add(DockPane pane)
+		{
+			if (pane == null)
+				return;
+
+			NestedPaneCollection oldNestedPanes = (pane.NestedPanesContainer == null) ? null : pane.NestedPanesContainer.NestedPanes;
+			if (oldNestedPanes != null)
+				oldNestedPanes.InternalRemove(pane);
+			Items.Add(pane);
+			if (oldNestedPanes != null)
+				oldNestedPanes.CheckFloatWindowDispose();
+		}
+
+		private void CheckFloatWindowDispose()
+		{
+			if (Count == 0 && Container.DockState == DockState.Float)
+			{
+				FloatWindow floatWindow = (FloatWindow)Container;
+				if (!floatWindow.Disposing && !floatWindow.IsDisposed)
+					NativeMethods.PostMessage(((FloatWindow)Container).Handle, FloatWindow.WM_CHECKDISPOSE, 0, 0);
+			}
+		}
+
+		internal void Remove(DockPane pane)
+		{
+			InternalRemove(pane);
+			CheckFloatWindowDispose();
+		}
+
+		private void InternalRemove(DockPane pane)
+		{
+			if (!Contains(pane))
+				return;
+
+			NestedDockingStatus statusPane = pane.NestedDockingStatus;
+			DockPane lastNestedPane = null;
+			for (int i=Count - 1; i> IndexOf(pane); i--)
+			{
+				if (this[i].NestedDockingStatus.PreviousPane == pane)
+				{
+					lastNestedPane = this[i];
+					break;
+				}
+			}
+
+			if (lastNestedPane != null)
+			{
+				int indexLastNestedPane = IndexOf(lastNestedPane);
+				Items.Remove(lastNestedPane);
+				Items[IndexOf(pane)] = lastNestedPane;
+				NestedDockingStatus lastNestedDock = lastNestedPane.NestedDockingStatus;
+				lastNestedDock.SetStatus(this, statusPane.PreviousPane, statusPane.Alignment, statusPane.Proportion);
+				for (int i=indexLastNestedPane - 1; i>IndexOf(lastNestedPane); i--)
+				{
+					NestedDockingStatus status = this[i].NestedDockingStatus;
+					if (status.PreviousPane == pane)
+						status.SetStatus(this, lastNestedPane, status.Alignment, status.Proportion);
+				}
+			}
+			else
+				Items.Remove(pane);
+
+			statusPane.SetStatus(null, null, DockAlignment.Left, 0.5);
+			statusPane.SetDisplayingStatus(false, null, DockAlignment.Left, 0.5);
+			statusPane.SetDisplayingBounds(Rectangle.Empty, Rectangle.Empty, Rectangle.Empty);
+		}
+
+		public DockPane GetDefaultPreviousPane(DockPane pane)
+		{
+			for (int i=Count-1; i>=0; i--)
+				if (this[i] != pane)
+					return this[i];
+
+			return null;
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Resources.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Resources.Designer.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Resources.Designer.cs	(revision 2645)
@@ -0,0 +1,224 @@
+﻿//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.4016
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace WeifenLuo.WinFormsUI.Docking {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WeifenLuo.WinFormsUI.Docking.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Bottom {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Bottom", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Fill {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Fill", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_HotSpot {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_HotSpot", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_HotSpotIndex {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_HotSpotIndex", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Left {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Left", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Right {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Right", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PaneDiamond_Top {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PaneDiamond_Top", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelBottom {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelBottom", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelBottom_Active {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelBottom_Active", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelFill {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelFill", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelFill_Active {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelFill_Active", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelLeft {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelLeft", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelLeft_Active {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelLeft_Active", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelRight {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelRight", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelRight_Active {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelRight_Active", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelTop {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelTop", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockIndicator_PanelTop_Active {
+            get {
+                object obj = ResourceManager.GetObject("DockIndicator_PanelTop_Active", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockPane_AutoHide {
+            get {
+                object obj = ResourceManager.GetObject("DockPane_AutoHide", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockPane_Close {
+            get {
+                object obj = ResourceManager.GetObject("DockPane_Close", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockPane_Dock {
+            get {
+                object obj = ResourceManager.GetObject("DockPane_Dock", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockPane_Option {
+            get {
+                object obj = ResourceManager.GetObject("DockPane_Option", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        internal static System.Drawing.Bitmap DockPane_OptionOverflow {
+            get {
+                object obj = ResourceManager.GetObject("DockPane_OptionOverflow", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Resources.resx
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Resources.resx	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Resources.resx	(revision 2645)
@@ -0,0 +1,190 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="DockIndicator_PaneDiamond" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_Bottom" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_Bottom.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_Fill" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_Fill.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_HotSpot" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_HotSpot.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_HotSpotIndex" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_HotSpotIndex.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_Left" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_Left.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_Right" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_Right.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PaneDiamond_Top" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PaneDiamond_Top.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelBottom" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelBottom.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelBottom_Active" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelBottom_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelFill" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelFill.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelFill_Active" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelFill_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelLeft" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelLeft.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelLeft_Active" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelLeft_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelRight" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelRight.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelRight_Active" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelRight_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelTop" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelTop.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockIndicator_PanelTop_Active" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockIndicator_PanelTop_Active.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockPane_AutoHide" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockPane_AutoHide.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockPane_Close" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockPane_Close.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockPane_Dock" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockPane_Dock.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockPane_Option" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockPane_Option.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="DockPane_OptionOverflow" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\DockPane_OptionOverflow.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+</root>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/SplitterBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/SplitterBase.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/SplitterBase.cs	(revision 2645)
@@ -0,0 +1,70 @@
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal class SplitterBase : Control
+	{
+		public SplitterBase()
+		{
+			SetStyle(ControlStyles.Selectable, false);
+		}
+
+		public override DockStyle Dock
+		{
+			get	{	return base.Dock;	}
+			set
+			{
+				SuspendLayout();
+				base.Dock = value;
+
+				if (Dock == DockStyle.Left || Dock == DockStyle.Right)
+					Width = SplitterSize;
+				else if (Dock == DockStyle.Top || Dock == DockStyle.Bottom)
+					Height = SplitterSize;
+				else
+					Bounds = Rectangle.Empty;
+
+				if (Dock == DockStyle.Left || Dock == DockStyle.Right)
+					Cursor = Cursors.VSplit;
+				else if (Dock == DockStyle.Top || Dock == DockStyle.Bottom)
+					Cursor = Cursors.HSplit;
+				else
+					Cursor = Cursors.Default;
+					
+				ResumeLayout();
+			}
+		}
+
+		protected virtual int SplitterSize
+		{
+			get	{	return 0;	}
+		}
+
+		protected override void OnMouseDown(MouseEventArgs e)
+		{
+			base.OnMouseDown(e);
+
+			if (e.Button != MouseButtons.Left)
+				return;
+
+			StartDrag();
+		}
+
+		protected virtual void StartDrag()
+		{
+		}
+
+		protected override void WndProc(ref Message m)
+		{
+            // eat the WM_MOUSEACTIVATE message
+			if (m.Msg == (int)Win32.Msgs.WM_MOUSEACTIVATE)
+				return;
+
+			base.WndProc(ref m);
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Strings.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Strings.Designer.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Strings.Designer.cs	(revision 2645)
@@ -0,0 +1,774 @@
+﻿//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.4016
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace WeifenLuo.WinFormsUI.Docking {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Strings {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Strings() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WeifenLuo.WinFormsUI.Docking.Strings", typeof(Strings).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Docking.
+        /// </summary>
+        internal static string Category_Docking {
+            get {
+                return ResourceManager.GetString("Category_Docking", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Docking Notification.
+        /// </summary>
+        internal static string Category_DockingNotification {
+            get {
+                return ResourceManager.GetString("Category_DockingNotification", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Property Changed.
+        /// </summary>
+        internal static string Category_PropertyChanged {
+            get {
+                return ResourceManager.GetString("Category_PropertyChanged", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to (Float).
+        /// </summary>
+        internal static string DockAreaEditor_FloatCheckBoxText {
+            get {
+                return ResourceManager.GetString("DockAreaEditor_FloatCheckBoxText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Determines if end user drag and drop docking is allowed..
+        /// </summary>
+        internal static string DockContent_AllowEndUserDocking_Description {
+            get {
+                return ResourceManager.GetString("DockContent_AllowEndUserDocking_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The size to display the content in auto hide mode. Value &lt; 1 to specify the size in portion; value &gt;= 1 to specify the size in pixel..
+        /// </summary>
+        internal static string DockContent_AutoHidePortion_Description {
+            get {
+                return ResourceManager.GetString("DockContent_AutoHidePortion_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Enable/Disable the close button of the content..
+        /// </summary>
+        internal static string DockContent_CloseButton_Description {
+            get {
+                return ResourceManager.GetString("DockContent_CloseButton_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Shows or hides the close button of the content. This property does not function with System MDI Document Style..
+        /// </summary>
+        internal static string DockContent_CloseButtonVisible_Description {
+            get {
+                return ResourceManager.GetString("DockContent_CloseButtonVisible_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The form must be of type IDockContent..
+        /// </summary>
+        internal static string DockContent_Constructor_InvalidForm {
+            get {
+                return ResourceManager.GetString("DockContent_Constructor_InvalidForm", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Gets or sets a value indicating in which area of the DockPanel the content allowed to show..
+        /// </summary>
+        internal static string DockContent_DockAreas_Description {
+            get {
+                return ResourceManager.GetString("DockContent_DockAreas_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Occurs when the value of DockState property changed..
+        /// </summary>
+        internal static string DockContent_DockStateChanged_Description {
+            get {
+                return ResourceManager.GetString("DockContent_DockStateChanged_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Indicates the content will be hidden instead of being closed..
+        /// </summary>
+        internal static string DockContent_HideOnClose_Description {
+            get {
+                return ResourceManager.GetString("DockContent_HideOnClose_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The desired docking state when first showing..
+        /// </summary>
+        internal static string DockContent_ShowHint_Description {
+            get {
+                return ResourceManager.GetString("DockContent_ShowHint_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Context menu displayed for the dock pane tab strip..
+        /// </summary>
+        internal static string DockContent_TabPageContextMenu_Description {
+            get {
+                return ResourceManager.GetString("DockContent_TabPageContextMenu_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The tab text displayed in the dock pane. If not set, the Text property will be used..
+        /// </summary>
+        internal static string DockContent_TabText_Description {
+            get {
+                return ResourceManager.GetString("DockContent_TabText_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The text displayed when mouse hovers over the tab..
+        /// </summary>
+        internal static string DockContent_ToolTipText_Description {
+            get {
+                return ResourceManager.GetString("DockContent_ToolTipText_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The provided value is out of range..
+        /// </summary>
+        internal static string DockContentHandler_AutoHidePortion_OutOfRange {
+            get {
+                return ResourceManager.GetString("DockContentHandler_AutoHidePortion_OutOfRange", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Value: The value of DockAreas conflicts with current DockState..
+        /// </summary>
+        internal static string DockContentHandler_DockAreas_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockContentHandler_DockAreas_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane..
+        /// </summary>
+        internal static string DockContentHandler_DockPane_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockContentHandler_DockPane_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane..
+        /// </summary>
+        internal static string DockContentHandler_FloatPane_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockContentHandler_FloatPane_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid value, conflicts with DockableAreas  property..
+        /// </summary>
+        internal static string DockContentHandler_IsFloat_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockContentHandler_IsFloat_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The dock state is invalid..
+        /// </summary>
+        internal static string DockContentHandler_SetDockState_InvalidState {
+            get {
+                return ResourceManager.GetString("DockContentHandler_SetDockState_InvalidState", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The dock panel is null..
+        /// </summary>
+        internal static string DockContentHandler_SetDockState_NullPanel {
+            get {
+                return ResourceManager.GetString("DockContentHandler_SetDockState_NullPanel", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid beforeContent, it must be contained by the pane..
+        /// </summary>
+        internal static string DockContentHandler_Show_InvalidBeforeContent {
+            get {
+                return ResourceManager.GetString("DockContentHandler_Show_InvalidBeforeContent", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid DockState: Content can not be showed as &quot;Unknown&quot; or &quot;Hidden&quot;..
+        /// </summary>
+        internal static string DockContentHandler_Show_InvalidDockState {
+            get {
+                return ResourceManager.GetString("DockContentHandler_Show_InvalidDockState", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The previous pane is invalid. It can not be null, and its docking state must not be auto-hide..
+        /// </summary>
+        internal static string DockContentHandler_Show_InvalidPrevPane {
+            get {
+                return ResourceManager.GetString("DockContentHandler_Show_InvalidPrevPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to DockPanel can not be null..
+        /// </summary>
+        internal static string DockContentHandler_Show_NullDockPanel {
+            get {
+                return ResourceManager.GetString("DockContentHandler_Show_NullDockPanel", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The Pane can not be null..
+        /// </summary>
+        internal static string DockContentHandler_Show_NullPane {
+            get {
+                return ResourceManager.GetString("DockContentHandler_Show_NullPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid value, check DockableAreas property..
+        /// </summary>
+        internal static string DockContentHandler_ShowHint_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockContentHandler_ShowHint_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Context menu displayed for the dock pane tab strip..
+        /// </summary>
+        internal static string DockHandler_TabPageContextMenuStrip_Description {
+            get {
+                return ResourceManager.GetString("DockHandler_TabPageContextMenuStrip_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Press SHIFT for docking to full side..
+        /// </summary>
+        internal static string DockIndicator_ToolTipText {
+            get {
+                return ResourceManager.GetString("DockIndicator_ToolTipText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content..
+        /// </summary>
+        internal static string DockPane_ActiveContent_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockPane_ActiveContent_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid argument: Content can not be &quot;null&quot;..
+        /// </summary>
+        internal static string DockPane_Constructor_NullContent {
+            get {
+                return ResourceManager.GetString("DockPane_Constructor_NullContent", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid argument: The content&apos;s DockPanel can not be &quot;null&quot;..
+        /// </summary>
+        internal static string DockPane_Constructor_NullDockPanel {
+            get {
+                return ResourceManager.GetString("DockPane_Constructor_NullDockPanel", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The specified container conflicts with the IsFloat property..
+        /// </summary>
+        internal static string DockPane_DockTo_InvalidContainer {
+            get {
+                return ResourceManager.GetString("DockPane_DockTo_InvalidContainer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The previous pane does not exist in the nested docking pane collection..
+        /// </summary>
+        internal static string DockPane_DockTo_NoPrevPane {
+            get {
+                return ResourceManager.GetString("DockPane_DockTo_NoPrevPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The container can not be null..
+        /// </summary>
+        internal static string DockPane_DockTo_NullContainer {
+            get {
+                return ResourceManager.GetString("DockPane_DockTo_NullContainer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The previous pane can not be null when the nested docking pane collection is not empty..
+        /// </summary>
+        internal static string DockPane_DockTo_NullPrevPane {
+            get {
+                return ResourceManager.GetString("DockPane_DockTo_NullPrevPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The previous pane can not be itself..
+        /// </summary>
+        internal static string DockPane_DockTo_SelfPrevPane {
+            get {
+                return ResourceManager.GetString("DockPane_DockTo_SelfPrevPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to FloatWindow property can not be set to &quot;null&quot; when DockState is DockState.Float..
+        /// </summary>
+        internal static string DockPane_FloatWindow_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockPane_FloatWindow_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Content: Content not within the collection..
+        /// </summary>
+        internal static string DockPane_SetContentIndex_InvalidContent {
+            get {
+                return ResourceManager.GetString("DockPane_SetContentIndex_InvalidContent", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Index: The index is out of range..
+        /// </summary>
+        internal static string DockPane_SetContentIndex_InvalidIndex {
+            get {
+                return ResourceManager.GetString("DockPane_SetContentIndex_InvalidIndex", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The state for the dock pane is invalid..
+        /// </summary>
+        internal static string DockPane_SetDockState_InvalidState {
+            get {
+                return ResourceManager.GetString("DockPane_SetDockState_InvalidState", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Auto Hide.
+        /// </summary>
+        internal static string DockPaneCaption_ToolTipAutoHide {
+            get {
+                return ResourceManager.GetString("DockPaneCaption_ToolTipAutoHide", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Close.
+        /// </summary>
+        internal static string DockPaneCaption_ToolTipClose {
+            get {
+                return ResourceManager.GetString("DockPaneCaption_ToolTipClose", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Options.
+        /// </summary>
+        internal static string DockPaneCaption_ToolTipOptions {
+            get {
+                return ResourceManager.GetString("DockPaneCaption_ToolTipOptions", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Content: The content must be auto-hide state and associates with this DockPanel..
+        /// </summary>
+        internal static string DockPanel_ActiveAutoHideContent_InvalidValue {
+            get {
+                return ResourceManager.GetString("DockPanel_ActiveAutoHideContent_InvalidValue", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Occurs when the value of ActiveContentProperty changed..
+        /// </summary>
+        internal static string DockPanel_ActiveContentChanged_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_ActiveContentChanged_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Occurs when the value of ActiveDocument property changed..
+        /// </summary>
+        internal static string DockPanel_ActiveDocumentChanged_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_ActiveDocumentChanged_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Occurs when the value of ActivePane property changed..
+        /// </summary>
+        internal static string DockPanel_ActivePaneChanged_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_ActivePaneChanged_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Determines if the drag and drop docking is allowed..
+        /// </summary>
+        internal static string DockPanel_AllowEndUserDocking_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_AllowEndUserDocking_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Determines if the drag and drop nested docking is allowed..
+        /// </summary>
+        internal static string DockPanel_AllowEndUserNestedDocking_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_AllowEndUserNestedDocking_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Occurs when a content added to the DockPanel..
+        /// </summary>
+        internal static string DockPanel_ContentAdded_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_ContentAdded_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Occurs when a content removed from the DockPanel..
+        /// </summary>
+        internal static string DockPanel_ContentRemoved_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_ContentRemoved_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The default size of float window..
+        /// </summary>
+        internal static string DockPanel_DefaultFloatWindowSize_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_DefaultFloatWindowSize_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Provides Visual Studio .Net style docking..
+        /// </summary>
+        internal static string DockPanel_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Size of the bottom docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels..
+        /// </summary>
+        internal static string DockPanel_DockBottomPortion_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_DockBottomPortion_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Size of the left docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels..
+        /// </summary>
+        internal static string DockPanel_DockLeftPortion_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_DockLeftPortion_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The visual skin to use when displaying the docked windows..
+        /// </summary>
+        internal static string DockPanel_DockPanelSkin {
+            get {
+                return ResourceManager.GetString("DockPanel_DockPanelSkin", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Size of the right docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels..
+        /// </summary>
+        internal static string DockPanel_DockRightPortion_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_DockRightPortion_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Size of the top docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels..
+        /// </summary>
+        internal static string DockPanel_DockTopPortion_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_DockTopPortion_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The style of the document window..
+        /// </summary>
+        internal static string DockPanel_DocumentStyle_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_DocumentStyle_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Determines where the tab strip for Document style content is drawn..
+        /// </summary>
+        internal static string DockPanel_DocumentTabStripLocation {
+            get {
+                return ResourceManager.GetString("DockPanel_DocumentTabStripLocation", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The DockPanel has already been initialized..
+        /// </summary>
+        internal static string DockPanel_LoadFromXml_AlreadyInitialized {
+            get {
+                return ResourceManager.GetString("DockPanel_LoadFromXml_AlreadyInitialized", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The configuration file&apos;s version is invalid..
+        /// </summary>
+        internal static string DockPanel_LoadFromXml_InvalidFormatVersion {
+            get {
+                return ResourceManager.GetString("DockPanel_LoadFromXml_InvalidFormatVersion", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The XML file format is invalid..
+        /// </summary>
+        internal static string DockPanel_LoadFromXml_InvalidXmlFormat {
+            get {
+                return ResourceManager.GetString("DockPanel_LoadFromXml_InvalidXmlFormat", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid parent form. When using DockingMdi or SystemMdi document style, the DockPanel control must be the child control of the main MDI container form..
+        /// </summary>
+        internal static string DockPanel_ParentForm_Invalid {
+            get {
+                return ResourceManager.GetString("DockPanel_ParentForm_Invalid", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to DockPanel configuration file. Author: Weifen Luo, all rights reserved..
+        /// </summary>
+        internal static string DockPanel_Persistor_XmlFileComment1 {
+            get {
+                return ResourceManager.GetString("DockPanel_Persistor_XmlFileComment1", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!!.
+        /// </summary>
+        internal static string DockPanel_Persistor_XmlFileComment2 {
+            get {
+                return ResourceManager.GetString("DockPanel_Persistor_XmlFileComment2", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Indicates whether the control layout is right-to-left when the RightToLeft property is set to Yes..
+        /// </summary>
+        internal static string DockPanel_RightToLeftLayout_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_RightToLeftLayout_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Index: The index is out of range..
+        /// </summary>
+        internal static string DockPanel_SetPaneIndex_InvalidIndex {
+            get {
+                return ResourceManager.GetString("DockPanel_SetPaneIndex_InvalidIndex", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Pane: DockPane not within the collection..
+        /// </summary>
+        internal static string DockPanel_SetPaneIndex_InvalidPane {
+            get {
+                return ResourceManager.GetString("DockPanel_SetPaneIndex_InvalidPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Determines if the document icon will be displayed in the tab strip..
+        /// </summary>
+        internal static string DockPanel_ShowDocumentIcon_Description {
+            get {
+                return ResourceManager.GetString("DockPanel_ShowDocumentIcon_Description", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Close.
+        /// </summary>
+        internal static string DockPaneStrip_ToolTipClose {
+            get {
+                return ResourceManager.GetString("DockPaneStrip_ToolTipClose", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Window List.
+        /// </summary>
+        internal static string DockPaneStrip_ToolTipWindowList {
+            get {
+                return ResourceManager.GetString("DockPaneStrip_ToolTipWindowList", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid argument: DockPanel can not be &quot;null&quot;..
+        /// </summary>
+        internal static string FloatWindow_Constructor_NullDockPanel {
+            get {
+                return ResourceManager.GetString("FloatWindow_Constructor_NullDockPanel", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Index: The index is out of range..
+        /// </summary>
+        internal static string FloatWindow_SetPaneIndex_InvalidIndex {
+            get {
+                return ResourceManager.GetString("FloatWindow_SetPaneIndex_InvalidIndex", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid Pane: DockPane not within the collection..
+        /// </summary>
+        internal static string FloatWindow_SetPaneIndex_InvalidPane {
+            get {
+                return ResourceManager.GetString("FloatWindow_SetPaneIndex_InvalidPane", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Invalid DockPanel..
+        /// </summary>
+        internal static string IDockDragSource_DockTo_InvalidPanel {
+            get {
+                return ResourceManager.GetString("IDockDragSource_DockTo_InvalidPanel", resourceCulture);
+            }
+        }
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Strings.resx
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Strings.resx	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Strings.resx	(revision 2645)
@@ -0,0 +1,357 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="Category_Docking" xml:space="preserve">
+    <value>Docking</value>
+  </data>
+  <data name="Category_DockingNotification" xml:space="preserve">
+    <value>Docking Notification</value>
+  </data>
+  <data name="Category_PropertyChanged" xml:space="preserve">
+    <value>Property Changed</value>
+  </data>
+  <data name="DockAreaEditor_FloatCheckBoxText" xml:space="preserve">
+    <value>(Float)</value>
+  </data>
+  <data name="DockContent_AllowEndUserDocking_Description" xml:space="preserve">
+    <value>Determines if end user drag and drop docking is allowed.</value>
+  </data>
+  <data name="DockContent_AutoHidePortion_Description" xml:space="preserve">
+    <value>The size to display the content in auto hide mode. Value &lt; 1 to specify the size in portion; value &gt;= 1 to specify the size in pixel.</value>
+  </data>
+  <data name="DockContent_CloseButton_Description" xml:space="preserve">
+    <value>Enable/Disable the close button of the content.</value>
+  </data>
+  <data name="DockContent_Constructor_InvalidForm" xml:space="preserve">
+    <value>The form must be of type IDockContent.</value>
+  </data>
+  <data name="DockContent_DockAreas_Description" xml:space="preserve">
+    <value>Gets or sets a value indicating in which area of the DockPanel the content allowed to show.</value>
+  </data>
+  <data name="DockContent_DockStateChanged_Description" xml:space="preserve">
+    <value>Occurs when the value of DockState property changed.</value>
+  </data>
+  <data name="DockContent_HideOnClose_Description" xml:space="preserve">
+    <value>Indicates the content will be hidden instead of being closed.</value>
+  </data>
+  <data name="DockContent_ShowHint_Description" xml:space="preserve">
+    <value>The desired docking state when first showing.</value>
+  </data>
+  <data name="DockContent_TabPageContextMenu_Description" xml:space="preserve">
+    <value>Context menu displayed for the dock pane tab strip.</value>
+  </data>
+  <data name="DockContent_TabText_Description" xml:space="preserve">
+    <value>The tab text displayed in the dock pane. If not set, the Text property will be used.</value>
+  </data>
+  <data name="DockContent_ToolTipText_Description" xml:space="preserve">
+    <value>The text displayed when mouse hovers over the tab.</value>
+  </data>
+  <data name="DockContentHandler_AutoHidePortion_OutOfRange" xml:space="preserve">
+    <value>The provided value is out of range.</value>
+  </data>
+  <data name="DockContentHandler_DockAreas_InvalidValue" xml:space="preserve">
+    <value>Invalid Value: The value of DockAreas conflicts with current DockState.</value>
+  </data>
+  <data name="DockContentHandler_DockPane_InvalidValue" xml:space="preserve">
+    <value>The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane.</value>
+  </data>
+  <data name="DockContentHandler_FloatPane_InvalidValue" xml:space="preserve">
+    <value>The pane is invalid. Check the IsFloat and DockPanel properties of this dock pane.</value>
+  </data>
+  <data name="DockContentHandler_IsFloat_InvalidValue" xml:space="preserve">
+    <value>Invalid value, conflicts with DockableAreas  property.</value>
+  </data>
+  <data name="DockContentHandler_SetDockState_InvalidState" xml:space="preserve">
+    <value>The dock state is invalid.</value>
+  </data>
+  <data name="DockContentHandler_SetDockState_NullPanel" xml:space="preserve">
+    <value>The dock panel is null.</value>
+  </data>
+  <data name="DockContentHandler_Show_InvalidBeforeContent" xml:space="preserve">
+    <value>Invalid beforeContent, it must be contained by the pane.</value>
+  </data>
+  <data name="DockContentHandler_Show_InvalidDockState" xml:space="preserve">
+    <value>Invalid DockState: Content can not be showed as "Unknown" or "Hidden".</value>
+  </data>
+  <data name="DockContentHandler_Show_InvalidPrevPane" xml:space="preserve">
+    <value>The previous pane is invalid. It can not be null, and its docking state must not be auto-hide.</value>
+  </data>
+  <data name="DockContentHandler_Show_NullDockPanel" xml:space="preserve">
+    <value>DockPanel can not be null.</value>
+  </data>
+  <data name="DockContentHandler_Show_NullPane" xml:space="preserve">
+    <value>The Pane can not be null.</value>
+  </data>
+  <data name="DockContentHandler_ShowHint_InvalidValue" xml:space="preserve">
+    <value>Invalid value, check DockableAreas property.</value>
+  </data>
+  <data name="DockHandler_TabPageContextMenuStrip_Description" xml:space="preserve">
+    <value>Context menu displayed for the dock pane tab strip.</value>
+  </data>
+  <data name="DockIndicator_ToolTipText" xml:space="preserve">
+    <value>Press SHIFT for docking to full side.</value>
+  </data>
+  <data name="DockPane_ActiveContent_InvalidValue" xml:space="preserve">
+    <value>Invalid Content: ActiveContent must be one of the visible contents, or null if there is no visible content.</value>
+  </data>
+  <data name="DockPane_Constructor_NullContent" xml:space="preserve">
+    <value>Invalid argument: Content can not be "null".</value>
+  </data>
+  <data name="DockPane_Constructor_NullDockPanel" xml:space="preserve">
+    <value>Invalid argument: The content's DockPanel can not be "null".</value>
+  </data>
+  <data name="DockPane_DockTo_InvalidContainer" xml:space="preserve">
+    <value>The specified container conflicts with the IsFloat property.</value>
+  </data>
+  <data name="DockPane_DockTo_NoPrevPane" xml:space="preserve">
+    <value>The previous pane does not exist in the nested docking pane collection.</value>
+  </data>
+  <data name="DockPane_DockTo_NullContainer" xml:space="preserve">
+    <value>The container can not be null.</value>
+  </data>
+  <data name="DockPane_DockTo_NullPrevPane" xml:space="preserve">
+    <value>The previous pane can not be null when the nested docking pane collection is not empty.</value>
+  </data>
+  <data name="DockPane_DockTo_SelfPrevPane" xml:space="preserve">
+    <value>The previous pane can not be itself.</value>
+  </data>
+  <data name="DockPane_FloatWindow_InvalidValue" xml:space="preserve">
+    <value>FloatWindow property can not be set to "null" when DockState is DockState.Float.</value>
+  </data>
+  <data name="DockPane_SetContentIndex_InvalidContent" xml:space="preserve">
+    <value>Invalid Content: Content not within the collection.</value>
+  </data>
+  <data name="DockPane_SetContentIndex_InvalidIndex" xml:space="preserve">
+    <value>Invalid Index: The index is out of range.</value>
+  </data>
+  <data name="DockPane_SetDockState_InvalidState" xml:space="preserve">
+    <value>The state for the dock pane is invalid.</value>
+  </data>
+  <data name="DockPaneCaption_ToolTipAutoHide" xml:space="preserve">
+    <value>Auto Hide</value>
+  </data>
+  <data name="DockPaneCaption_ToolTipClose" xml:space="preserve">
+    <value>Close</value>
+  </data>
+  <data name="DockPaneCaption_ToolTipOptions" xml:space="preserve">
+    <value>Options</value>
+  </data>
+  <data name="DockPanel_ActiveAutoHideContent_InvalidValue" xml:space="preserve">
+    <value>Invalid Content: The content must be auto-hide state and associates with this DockPanel.</value>
+  </data>
+  <data name="DockPanel_ActiveContentChanged_Description" xml:space="preserve">
+    <value>Occurs when the value of ActiveContentProperty changed.</value>
+  </data>
+  <data name="DockPanel_ActiveDocumentChanged_Description" xml:space="preserve">
+    <value>Occurs when the value of ActiveDocument property changed.</value>
+  </data>
+  <data name="DockPanel_ActivePaneChanged_Description" xml:space="preserve">
+    <value>Occurs when the value of ActivePane property changed.</value>
+  </data>
+  <data name="DockPanel_AllowEndUserDocking_Description" xml:space="preserve">
+    <value>Determines if the drag and drop docking is allowed.</value>
+  </data>
+  <data name="DockPanel_AllowEndUserNestedDocking_Description" xml:space="preserve">
+    <value>Determines if the drag and drop nested docking is allowed.</value>
+  </data>
+  <data name="DockPanel_ContentAdded_Description" xml:space="preserve">
+    <value>Occurs when a content added to the DockPanel.</value>
+  </data>
+  <data name="DockPanel_ContentRemoved_Description" xml:space="preserve">
+    <value>Occurs when a content removed from the DockPanel.</value>
+  </data>
+  <data name="DockPanel_DefaultFloatWindowSize_Description" xml:space="preserve">
+    <value>The default size of float window.</value>
+  </data>
+  <data name="DockPanel_Description" xml:space="preserve">
+    <value>Provides Visual Studio .Net style docking.</value>
+  </data>
+  <data name="DockPanel_DockBottomPortion_Description" xml:space="preserve">
+    <value>Size of the bottom docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels.</value>
+  </data>
+  <data name="DockPanel_DockLeftPortion_Description" xml:space="preserve">
+    <value>Size of the left docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels.</value>
+  </data>
+  <data name="DockPanel_DockRightPortion_Description" xml:space="preserve">
+    <value>Size of the right docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels.</value>
+  </data>
+  <data name="DockPanel_DockTopPortion_Description" xml:space="preserve">
+    <value>Size of the top docking window. Value &lt; 1 to specify the size in portion; value &gt; 1 to specify the size in pixels.</value>
+  </data>
+  <data name="DockPanel_DocumentStyle_Description" xml:space="preserve">
+    <value>The style of the document window.</value>
+  </data>
+  <data name="DockPanel_LoadFromXml_AlreadyInitialized" xml:space="preserve">
+    <value>The DockPanel has already been initialized.</value>
+  </data>
+  <data name="DockPanel_LoadFromXml_InvalidFormatVersion" xml:space="preserve">
+    <value>The configuration file's version is invalid.</value>
+  </data>
+  <data name="DockPanel_LoadFromXml_InvalidXmlFormat" xml:space="preserve">
+    <value>The XML file format is invalid.</value>
+  </data>
+  <data name="DockPanel_ParentForm_Invalid" xml:space="preserve">
+    <value>Invalid parent form. When using DockingMdi or SystemMdi document style, the DockPanel control must be the child control of the main MDI container form.</value>
+  </data>
+  <data name="DockPanel_Persistor_XmlFileComment1" xml:space="preserve">
+    <value>DockPanel configuration file. Author: Weifen Luo, all rights reserved.</value>
+  </data>
+  <data name="DockPanel_Persistor_XmlFileComment2" xml:space="preserve">
+    <value>!!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!!</value>
+  </data>
+  <data name="DockPanel_RightToLeftLayout_Description" xml:space="preserve">
+    <value>Indicates whether the control layout is right-to-left when the RightToLeft property is set to Yes.</value>
+  </data>
+  <data name="DockPanel_SetPaneIndex_InvalidIndex" xml:space="preserve">
+    <value>Invalid Index: The index is out of range.</value>
+  </data>
+  <data name="DockPanel_SetPaneIndex_InvalidPane" xml:space="preserve">
+    <value>Invalid Pane: DockPane not within the collection.</value>
+  </data>
+  <data name="DockPanel_ShowDocumentIcon_Description" xml:space="preserve">
+    <value>Determines if the document icon will be displayed in the tab strip.</value>
+  </data>
+  <data name="DockPaneStrip_ToolTipClose" xml:space="preserve">
+    <value>Close</value>
+  </data>
+  <data name="DockPaneStrip_ToolTipWindowList" xml:space="preserve">
+    <value>Window List</value>
+  </data>
+  <data name="FloatWindow_Constructor_NullDockPanel" xml:space="preserve">
+    <value>Invalid argument: DockPanel can not be "null".</value>
+  </data>
+  <data name="FloatWindow_SetPaneIndex_InvalidIndex" xml:space="preserve">
+    <value>Invalid Index: The index is out of range.</value>
+  </data>
+  <data name="FloatWindow_SetPaneIndex_InvalidPane" xml:space="preserve">
+    <value>Invalid Pane: DockPane not within the collection.</value>
+  </data>
+  <data name="IDockDragSource_DockTo_InvalidPanel" xml:space="preserve">
+    <value>Invalid DockPanel.</value>
+  </data>
+  <data name="DockContent_CloseButtonVisible_Description" xml:space="preserve">
+    <value>Shows or hides the close button of the content. This property does not function with System MDI Document Style.</value>
+  </data>
+  <data name="DockPanel_DockPanelSkin" xml:space="preserve">
+    <value>The visual skin to use when displaying the docked windows.</value>
+  </data>
+  <data name="DockPanel_DocumentTabStripLocation" xml:space="preserve">
+    <value>Determines where the tab strip for Document style content is drawn.</value>
+  </data>
+</root>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005AutoHideStrip.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005AutoHideStrip.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005AutoHideStrip.cs	(revision 2645)
@@ -0,0 +1,505 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Drawing.Drawing2D;
+using System.ComponentModel;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal class VS2005AutoHideStrip : AutoHideStripBase
+	{
+        private class TabVS2005 : Tab
+        {
+            internal TabVS2005(IDockContent content)
+                : base(content)
+            {
+            }
+
+            private int m_tabX = 0;
+            public int TabX
+            {
+                get { return m_tabX; }
+                set { m_tabX = value; }
+            }
+
+            private int m_tabWidth = 0;
+            public int TabWidth
+            {
+                get { return m_tabWidth; }
+                set { m_tabWidth = value; }
+            }
+
+        }
+
+		private const int _ImageHeight = 16;
+		private const int _ImageWidth = 16;
+		private const int _ImageGapTop = 2;
+		private const int _ImageGapLeft = 4;
+		private const int _ImageGapRight = 2;
+		private const int _ImageGapBottom = 2;
+		private const int _TextGapLeft = 0;
+		private const int _TextGapRight = 0;
+		private const int _TabGapTop = 3;
+		private const int _TabGapLeft = 4;
+		private const int _TabGapBetween = 10;
+
+		#region Customizable Properties
+        private static Font TextFont
+        {
+            get { return SystemInformation.MenuFont; }
+        }
+
+		private static StringFormat _stringFormatTabHorizontal;
+		private StringFormat StringFormatTabHorizontal
+		{
+			get
+			{
+				if (_stringFormatTabHorizontal == null)
+				{
+					_stringFormatTabHorizontal = new StringFormat();
+					_stringFormatTabHorizontal.Alignment = StringAlignment.Near;
+					_stringFormatTabHorizontal.LineAlignment = StringAlignment.Center;
+					_stringFormatTabHorizontal.FormatFlags = StringFormatFlags.NoWrap;
+				    _stringFormatTabHorizontal.Trimming = StringTrimming.None;
+				}
+
+                if (RightToLeft == RightToLeft.Yes)
+                    _stringFormatTabHorizontal.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
+                else
+                    _stringFormatTabHorizontal.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft;
+
+				return _stringFormatTabHorizontal;
+			}
+		}
+
+		private static StringFormat _stringFormatTabVertical;
+		private StringFormat StringFormatTabVertical
+		{
+			get
+			{	
+				if (_stringFormatTabVertical == null)
+				{
+					_stringFormatTabVertical = new StringFormat();
+					_stringFormatTabVertical.Alignment = StringAlignment.Near;
+					_stringFormatTabVertical.LineAlignment = StringAlignment.Center;
+					_stringFormatTabVertical.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.DirectionVertical;
+				    _stringFormatTabVertical.Trimming = StringTrimming.None;
+				}
+                if (RightToLeft == RightToLeft.Yes)
+                    _stringFormatTabVertical.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
+                else
+                    _stringFormatTabVertical.FormatFlags &= ~StringFormatFlags.DirectionRightToLeft;
+
+                return _stringFormatTabVertical;
+			}
+		}
+
+		private static int ImageHeight
+		{
+			get	{	return _ImageHeight;	}
+		}
+
+		private static int ImageWidth
+		{
+			get	{	return _ImageWidth;	}
+		}
+
+		private static int ImageGapTop
+		{
+			get	{	return _ImageGapTop;	}
+		}
+
+		private static int ImageGapLeft
+		{
+			get	{	return _ImageGapLeft;	}
+		}
+
+		private static int ImageGapRight
+		{
+			get	{	return _ImageGapRight;	}
+		}
+
+		private static int ImageGapBottom
+		{
+			get	{	return _ImageGapBottom;	}
+		}
+
+		private static int TextGapLeft
+		{
+			get	{	return _TextGapLeft;	}
+		}
+
+		private static int TextGapRight
+		{
+			get	{	return _TextGapRight;	}
+		}
+
+		private static int TabGapTop
+		{
+			get	{	return _TabGapTop;	}
+		}
+
+		private static int TabGapLeft
+		{
+			get	{	return _TabGapLeft;	}
+		}
+
+		private static int TabGapBetween
+		{
+			get	{	return _TabGapBetween;	}
+		}
+
+		private static Pen PenTabBorder
+		{
+			get	{	return SystemPens.GrayText;	}
+		}
+		#endregion
+
+        private static Matrix _matrixIdentity = new Matrix();
+        private static Matrix MatrixIdentity
+		{
+            get { return _matrixIdentity; }
+		}
+
+        private static DockState[] _dockStates;
+        private static DockState[] DockStates
+		{
+			get
+            {
+                if (_dockStates == null)
+                {
+                    _dockStates = new DockState[4];
+                    _dockStates[0] = DockState.DockLeftAutoHide;
+                    _dockStates[1] = DockState.DockRightAutoHide;
+                    _dockStates[2] = DockState.DockTopAutoHide;
+                    _dockStates[3] = DockState.DockBottomAutoHide;
+                }
+                return _dockStates;
+            }
+		}
+
+        private static GraphicsPath _graphicsPath;
+        internal static GraphicsPath GraphicsPath
+        {
+            get
+            {
+                if (_graphicsPath == null)
+                    _graphicsPath = new GraphicsPath();
+
+                return _graphicsPath;
+            }
+        }
+
+		public VS2005AutoHideStrip(DockPanel panel) : base(panel)
+		{
+			SetStyle(ControlStyles.ResizeRedraw | 
+                ControlStyles.UserPaint |
+                ControlStyles.AllPaintingInWmPaint |
+                ControlStyles.OptimizedDoubleBuffer, true);
+            BackColor = SystemColors.ControlLight;
+		}
+
+		protected override void OnPaint(PaintEventArgs e)
+		{
+			Graphics g = e.Graphics;
+            
+            Color startColor = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.StartColor;
+            Color endColor = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.EndColor;
+            LinearGradientMode gradientMode = DockPanel.Skin.AutoHideStripSkin.DockStripGradient.LinearGradientMode;
+            using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode))
+            {
+                g.FillRectangle(brush, ClientRectangle);
+            }
+			
+            DrawTabStrip(g);
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+			CalculateTabs();
+			base.OnLayout (levent);
+		}
+
+		private void DrawTabStrip(Graphics g)
+		{
+			DrawTabStrip(g, DockState.DockTopAutoHide);
+			DrawTabStrip(g, DockState.DockBottomAutoHide);
+			DrawTabStrip(g, DockState.DockLeftAutoHide);
+			DrawTabStrip(g, DockState.DockRightAutoHide);
+		}
+
+		private void DrawTabStrip(Graphics g, DockState dockState)
+		{
+			Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState);
+
+			if (rectTabStrip.IsEmpty)
+				return;
+
+            Matrix matrixIdentity = g.Transform;
+            if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide)
+			{
+				Matrix matrixRotated = new Matrix();
+				matrixRotated.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2,
+					(float)rectTabStrip.Y + (float)rectTabStrip.Height / 2));
+				g.Transform = matrixRotated;
+			}
+
+			foreach (Pane pane in GetPanes(dockState))
+			{
+				foreach (TabVS2005 tab in pane.AutoHideTabs)
+					DrawTab(g, tab);
+			}
+			g.Transform = matrixIdentity;
+		}
+
+		private void CalculateTabs()
+		{
+			CalculateTabs(DockState.DockTopAutoHide);
+			CalculateTabs(DockState.DockBottomAutoHide);
+			CalculateTabs(DockState.DockLeftAutoHide);
+			CalculateTabs(DockState.DockRightAutoHide);
+		}
+
+        private void CalculateTabs(DockState dockState)
+        {
+            Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState);
+
+            int imageHeight = rectTabStrip.Height - ImageGapTop - ImageGapBottom;
+            int imageWidth = ImageWidth;
+            if (imageHeight > ImageHeight)
+                imageWidth = ImageWidth * (imageHeight / ImageHeight);
+
+            int x = TabGapLeft + rectTabStrip.X;
+            foreach (Pane pane in GetPanes(dockState))
+            {
+                foreach (TabVS2005 tab in pane.AutoHideTabs)
+                {
+                    int width = imageWidth + ImageGapLeft + ImageGapRight +
+                        TextRenderer.MeasureText(tab.Content.DockHandler.TabText, TextFont).Width +
+                        TextGapLeft + TextGapRight;
+                    tab.TabX = x;
+                    tab.TabWidth = width;
+                    x += width;
+                }
+
+                x += TabGapBetween;
+            }
+        }
+
+        private Rectangle RtlTransform(Rectangle rect, DockState dockState)
+        {
+            Rectangle rectTransformed;
+            if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide)
+                rectTransformed = rect;
+            else
+                rectTransformed = DrawHelper.RtlTransform(this, rect);
+
+            return rectTransformed;
+        }
+
+        private GraphicsPath GetTabOutline(TabVS2005 tab, bool transformed, bool rtlTransform)
+        {
+            DockState dockState = tab.Content.DockHandler.DockState;
+            Rectangle rectTab = GetTabRectangle(tab, transformed);
+            if (rtlTransform)
+                rectTab = RtlTransform(rectTab, dockState);
+            bool upTab = (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockBottomAutoHide);
+            DrawHelper.GetRoundedCornerTab(GraphicsPath, rectTab, upTab);
+
+            return GraphicsPath;
+        }
+
+		private void DrawTab(Graphics g, TabVS2005 tab)
+		{
+			Rectangle rectTabOrigin = GetTabRectangle(tab);
+			if (rectTabOrigin.IsEmpty)
+				return;
+
+			DockState dockState = tab.Content.DockHandler.DockState;
+			IDockContent content = tab.Content;
+
+            GraphicsPath path = GetTabOutline(tab, false, true);
+
+            Color startColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.StartColor;
+            Color endColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.EndColor;
+            LinearGradientMode gradientMode = DockPanel.Skin.AutoHideStripSkin.TabGradient.LinearGradientMode;
+            g.FillPath(new LinearGradientBrush(rectTabOrigin, startColor, endColor, gradientMode), path);
+            g.DrawPath(PenTabBorder, path);
+
+            // Set no rotate for drawing icon and text
+			Matrix matrixRotate = g.Transform;
+			g.Transform = MatrixIdentity;
+
+			// Draw the icon
+			Rectangle rectImage = rectTabOrigin;
+			rectImage.X += ImageGapLeft;
+			rectImage.Y += ImageGapTop;
+			int imageHeight = rectTabOrigin.Height - ImageGapTop - ImageGapBottom;
+			int imageWidth = ImageWidth;
+			if (imageHeight > ImageHeight)
+				imageWidth = ImageWidth * (imageHeight/ImageHeight);
+			rectImage.Height = imageHeight;
+			rectImage.Width = imageWidth;
+			rectImage = GetTransformedRectangle(dockState, rectImage);
+			g.DrawIcon(((Form)content).Icon, RtlTransform(rectImage, dockState));
+
+			// Draw the text
+			Rectangle rectText = rectTabOrigin;
+			rectText.X += ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft;
+			rectText.Width -= ImageGapLeft + imageWidth + ImageGapRight + TextGapLeft;
+			rectText = RtlTransform(GetTransformedRectangle(dockState, rectText), dockState);
+
+            Color textColor = DockPanel.Skin.AutoHideStripSkin.TabGradient.TextColor;
+            
+			if (dockState == DockState.DockLeftAutoHide || dockState == DockState.DockRightAutoHide)
+				g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabVertical);
+			else
+                g.DrawString(content.DockHandler.TabText, TextFont, new SolidBrush(textColor), rectText, StringFormatTabHorizontal);
+
+			// Set rotate back
+			g.Transform = matrixRotate;
+		}
+
+		private Rectangle GetLogicalTabStripRectangle(DockState dockState)
+		{
+			return GetLogicalTabStripRectangle(dockState, false);
+		}
+
+		private Rectangle GetLogicalTabStripRectangle(DockState dockState, bool transformed)
+		{
+			if (!DockHelper.IsDockStateAutoHide(dockState))
+				return Rectangle.Empty;
+
+			int leftPanes = GetPanes(DockState.DockLeftAutoHide).Count;
+			int rightPanes = GetPanes(DockState.DockRightAutoHide).Count;
+			int topPanes = GetPanes(DockState.DockTopAutoHide).Count;
+			int bottomPanes = GetPanes(DockState.DockBottomAutoHide).Count;
+
+			int x, y, width, height;
+
+			height = MeasureHeight();
+			if (dockState == DockState.DockLeftAutoHide && leftPanes > 0)
+			{
+				x = 0;
+				y = (topPanes == 0) ? 0 : height;
+				width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 :height);
+			}
+			else if (dockState == DockState.DockRightAutoHide && rightPanes > 0)
+			{
+				x = Width - height;
+				if (leftPanes != 0 && x < height)
+					x = height;
+				y = (topPanes == 0) ? 0 : height;
+				width = Height - (topPanes == 0 ? 0 : height) - (bottomPanes == 0 ? 0 :height);
+			}
+			else if (dockState == DockState.DockTopAutoHide && topPanes > 0)
+			{
+				x = leftPanes == 0 ? 0 : height;
+				y = 0;
+				width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height);
+			}
+			else if (dockState == DockState.DockBottomAutoHide && bottomPanes > 0)
+			{
+				x = leftPanes == 0 ? 0 : height;
+				y = Height - height;
+				if (topPanes != 0 && y < height)
+					y = height;
+				width = Width - (leftPanes == 0 ? 0 : height) - (rightPanes == 0 ? 0 : height);
+			}
+			else
+				return Rectangle.Empty;
+
+			if (!transformed)
+				return new Rectangle(x, y, width, height);
+			else
+				return GetTransformedRectangle(dockState, new Rectangle(x, y, width, height));
+		}
+
+		private Rectangle GetTabRectangle(TabVS2005 tab)
+		{
+			return GetTabRectangle(tab, false);
+		}
+
+		private Rectangle GetTabRectangle(TabVS2005 tab, bool transformed)
+		{
+			DockState dockState = tab.Content.DockHandler.DockState;
+			Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState);
+
+			if (rectTabStrip.IsEmpty)
+				return Rectangle.Empty;
+
+			int x = tab.TabX;
+			int y = rectTabStrip.Y + 
+				(dockState == DockState.DockTopAutoHide || dockState == DockState.DockRightAutoHide ?
+				0 : TabGapTop);
+			int width = tab.TabWidth;
+			int height = rectTabStrip.Height - TabGapTop;
+
+			if (!transformed)
+				return new Rectangle(x, y, width, height);
+			else
+				return GetTransformedRectangle(dockState, new Rectangle(x, y, width, height));
+		}
+
+		private Rectangle GetTransformedRectangle(DockState dockState, Rectangle rect)
+		{
+			if (dockState != DockState.DockLeftAutoHide && dockState != DockState.DockRightAutoHide)
+				return rect;
+
+			PointF[] pts = new PointF[1];
+			// the center of the rectangle
+			pts[0].X = (float)rect.X + (float)rect.Width / 2;
+			pts[0].Y = (float)rect.Y + (float)rect.Height / 2;
+			Rectangle rectTabStrip = GetLogicalTabStripRectangle(dockState);
+			Matrix matrix = new Matrix();
+			matrix.RotateAt(90, new PointF((float)rectTabStrip.X + (float)rectTabStrip.Height / 2,
+				(float)rectTabStrip.Y + (float)rectTabStrip.Height / 2));
+			matrix.TransformPoints(pts);
+
+			return new Rectangle((int)(pts[0].X - (float)rect.Height / 2 + .5F),
+				(int)(pts[0].Y - (float)rect.Width / 2 + .5F),
+				rect.Height, rect.Width);
+		}
+
+		protected override IDockContent HitTest(Point ptMouse)
+		{
+			foreach(DockState state in DockStates)
+			{
+				Rectangle rectTabStrip = GetLogicalTabStripRectangle(state, true);
+				if (!rectTabStrip.Contains(ptMouse))
+					continue;
+
+				foreach(Pane pane in GetPanes(state))
+				{
+                    DockState dockState = pane.DockPane.DockState;
+					foreach(TabVS2005 tab in pane.AutoHideTabs)
+					{
+                        GraphicsPath path = GetTabOutline(tab, true, true);
+                        if (path.IsVisible(ptMouse))
+							return tab.Content;
+					}
+				}
+			}
+			
+			return null;
+		}
+
+		protected internal override int MeasureHeight()
+		{
+			return Math.Max(ImageGapBottom +
+				ImageGapTop + ImageHeight,
+				TextFont.Height) + TabGapTop;
+		}
+
+		protected override void OnRefreshChanges()
+		{
+			CalculateTabs();
+			Invalidate();
+		}
+
+        protected override AutoHideStripBase.Tab CreateTab(IDockContent content)
+        {
+            return new TabVS2005(content);
+        }
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005DockPaneCaption.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005DockPaneCaption.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005DockPaneCaption.cs	(revision 2645)
@@ -0,0 +1,478 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using System.ComponentModel;
+using System.Windows.Forms.VisualStyles;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal class VS2005DockPaneCaption : DockPaneCaptionBase
+	{
+        private sealed class InertButton : InertButtonBase
+        {
+            private Bitmap m_image, m_imageAutoHide;
+
+            public InertButton(VS2005DockPaneCaption dockPaneCaption, Bitmap image, Bitmap imageAutoHide)
+                : base()
+            {
+                m_dockPaneCaption = dockPaneCaption;
+                m_image = image;
+                m_imageAutoHide = imageAutoHide;
+                RefreshChanges();
+            }
+
+            private VS2005DockPaneCaption m_dockPaneCaption;
+            private VS2005DockPaneCaption DockPaneCaption
+            {
+                get { return m_dockPaneCaption; }
+            }
+
+            public bool IsAutoHide
+            {
+                get { return DockPaneCaption.DockPane.IsAutoHide; }
+            }
+
+            public override Bitmap Image
+            {
+                get { return IsAutoHide ? m_imageAutoHide : m_image; }
+            }
+
+            protected override void OnRefreshChanges()
+            {
+                if (DockPaneCaption.DockPane.DockPanel != null)
+                {
+                    if (DockPaneCaption.TextColor != ForeColor)
+                    {
+                        ForeColor = DockPaneCaption.TextColor;
+                        Invalidate();
+                    }
+                }
+            }
+        }
+
+		#region consts
+		private const int _TextGapTop = 2;
+		private const int _TextGapBottom = 0;
+		private const int _TextGapLeft = 3;
+		private const int _TextGapRight = 3;
+		private const int _ButtonGapTop = 2;
+		private const int _ButtonGapBottom = 1;
+		private const int _ButtonGapBetween = 1;
+		private const int _ButtonGapLeft = 1;
+		private const int _ButtonGapRight = 2;
+		#endregion
+
+        private static Bitmap _imageButtonClose;
+        private static Bitmap ImageButtonClose
+        {
+            get
+            {
+                if (_imageButtonClose == null)
+                    _imageButtonClose = Resources.DockPane_Close;
+
+                return _imageButtonClose;
+            }
+        }
+
+		private InertButton m_buttonClose;
+        private InertButton ButtonClose
+        {
+            get
+            {
+                if (m_buttonClose == null)
+                {
+                    m_buttonClose = new InertButton(this, ImageButtonClose, ImageButtonClose);
+                    m_toolTip.SetToolTip(m_buttonClose, ToolTipClose);
+                    m_buttonClose.Click += new EventHandler(Close_Click);
+                    Controls.Add(m_buttonClose);
+                }
+
+                return m_buttonClose;
+            }
+        }
+
+        private static Bitmap _imageButtonAutoHide;
+        private static Bitmap ImageButtonAutoHide
+        {
+            get
+            {
+                if (_imageButtonAutoHide == null)
+                    _imageButtonAutoHide = Resources.DockPane_AutoHide;
+
+                return _imageButtonAutoHide;
+            }
+        }
+
+        private static Bitmap _imageButtonDock;
+        private static Bitmap ImageButtonDock
+        {
+            get
+            {
+                if (_imageButtonDock == null)
+                    _imageButtonDock = Resources.DockPane_Dock;
+
+                return _imageButtonDock;
+            }
+        }
+
+        private InertButton m_buttonAutoHide;
+        private InertButton ButtonAutoHide
+        {
+            get
+            {
+                if (m_buttonAutoHide == null)
+                {
+                    m_buttonAutoHide = new InertButton(this, ImageButtonDock, ImageButtonAutoHide);
+                    m_toolTip.SetToolTip(m_buttonAutoHide, ToolTipAutoHide);
+                    m_buttonAutoHide.Click += new EventHandler(AutoHide_Click);
+                    Controls.Add(m_buttonAutoHide);
+                }
+
+                return m_buttonAutoHide;
+            }
+        }
+
+        private static Bitmap _imageButtonOptions;
+        private static Bitmap ImageButtonOptions
+        {
+            get
+            {
+                if (_imageButtonOptions == null)
+                    _imageButtonOptions = Resources.DockPane_Option;
+
+                return _imageButtonOptions;
+            }
+        }
+
+        private InertButton m_buttonOptions;
+        private InertButton ButtonOptions
+        {
+            get
+            {
+                if (m_buttonOptions == null)
+                {
+                    m_buttonOptions = new InertButton(this, ImageButtonOptions, ImageButtonOptions);
+                    m_toolTip.SetToolTip(m_buttonOptions, ToolTipOptions);
+                    m_buttonOptions.Click += new EventHandler(Options_Click);
+                    Controls.Add(m_buttonOptions);
+                }
+                return m_buttonOptions;
+            }
+        }
+
+        private IContainer m_components;
+        private IContainer Components
+        {
+            get { return m_components; }
+        }
+
+		private ToolTip m_toolTip;
+
+		public VS2005DockPaneCaption(DockPane pane) : base(pane)
+		{
+			SuspendLayout();
+
+            m_components = new Container();
+            m_toolTip = new ToolTip(Components);
+
+			ResumeLayout();
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+                Components.Dispose();
+            base.Dispose(disposing);
+        }
+
+		private static int TextGapTop
+		{
+			get	{	return _TextGapTop;	}
+		}
+
+        private static Font TextFont
+        {
+            get { return SystemInformation.MenuFont; }
+        }
+
+		private static int TextGapBottom
+		{
+			get	{	return _TextGapBottom;	}
+		}
+
+		private static int TextGapLeft
+		{
+			get	{	return _TextGapLeft;	}
+		}
+
+		private static int TextGapRight
+		{
+			get	{	return _TextGapRight;	}
+		}
+
+		private static int ButtonGapTop
+		{
+			get	{	return _ButtonGapTop;	}
+		}
+
+		private static int ButtonGapBottom
+		{
+			get	{	return _ButtonGapBottom;	}
+		}
+
+		private static int ButtonGapLeft
+		{
+			get	{	return _ButtonGapLeft;	}
+		}
+
+		private static int ButtonGapRight
+		{
+			get	{	return _ButtonGapRight;	}
+		}
+
+		private static int ButtonGapBetween
+		{
+			get	{	return _ButtonGapBetween;	}
+		}
+
+		private static string _toolTipClose;
+		private static string ToolTipClose
+		{
+			get
+			{	
+				if (_toolTipClose == null)
+					_toolTipClose = Strings.DockPaneCaption_ToolTipClose;
+				return _toolTipClose;
+			}
+		}
+
+        private static string _toolTipOptions;
+        private static string ToolTipOptions
+        {
+            get
+            {
+                if (_toolTipOptions == null)
+                    _toolTipOptions = Strings.DockPaneCaption_ToolTipOptions;
+
+                return _toolTipOptions;
+            }
+        }
+
+		private static string _toolTipAutoHide;
+		private static string ToolTipAutoHide
+		{
+			get
+			{	
+				if (_toolTipAutoHide == null)
+					_toolTipAutoHide = Strings.DockPaneCaption_ToolTipAutoHide;
+				return _toolTipAutoHide;
+			}
+		}
+
+        private static Blend _activeBackColorGradientBlend;
+        private static Blend ActiveBackColorGradientBlend
+        {
+            get
+            {
+                if (_activeBackColorGradientBlend == null)
+                {
+                    Blend blend = new Blend(2);
+
+                    blend.Factors = new float[]{0.5F, 1.0F};
+                    blend.Positions = new float[]{0.0F, 1.0F};
+                    _activeBackColorGradientBlend = blend;
+                }
+
+                return _activeBackColorGradientBlend;
+            }
+        }
+
+        private Color TextColor
+        {
+            get
+            {
+                if (DockPane.IsActivated)
+                    return DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor;
+                else
+                    return DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor;
+            }
+        }
+
+		private static TextFormatFlags _textFormat =
+            TextFormatFlags.SingleLine |
+            TextFormatFlags.EndEllipsis |
+            TextFormatFlags.VerticalCenter;
+		private TextFormatFlags TextFormat
+		{
+            get
+            {
+                if (RightToLeft == RightToLeft.No)
+                    return _textFormat;
+                else
+                    return _textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right;
+            }
+		}
+
+		protected internal override int MeasureHeight()
+		{
+			int height = TextFont.Height + TextGapTop + TextGapBottom;
+
+			if (height < ButtonClose.Image.Height + ButtonGapTop + ButtonGapBottom)
+				height = ButtonClose.Image.Height + ButtonGapTop + ButtonGapBottom;
+
+			return height;
+		}
+
+		protected override void OnPaint(PaintEventArgs e)
+		{
+			base.OnPaint (e);
+			DrawCaption(e.Graphics);
+		}
+
+		private void DrawCaption(Graphics g)
+		{
+            if (ClientRectangle.Width == 0 || ClientRectangle.Height == 0)
+                return;
+
+            if (DockPane.IsActivated)
+            {
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.LinearGradientMode;
+                using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode))
+                {
+                    brush.Blend = ActiveBackColorGradientBlend;
+                    g.FillRectangle(brush, ClientRectangle);
+                }
+            }
+            else
+            {
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.LinearGradientMode;
+                using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, startColor, endColor, gradientMode))
+                {
+                    g.FillRectangle(brush, ClientRectangle);
+                }
+            }
+
+			Rectangle rectCaption = ClientRectangle;
+
+			Rectangle rectCaptionText = rectCaption;
+            rectCaptionText.X += TextGapLeft;
+            rectCaptionText.Width -= TextGapLeft + TextGapRight;
+            rectCaptionText.Width -= ButtonGapLeft + ButtonClose.Width + ButtonGapRight;
+            if (ShouldShowAutoHideButton)
+                rectCaptionText.Width -= ButtonAutoHide.Width + ButtonGapBetween;
+            if (HasTabPageContextMenu)
+                rectCaptionText.Width -= ButtonOptions.Width + ButtonGapBetween;
+			rectCaptionText.Y += TextGapTop;
+			rectCaptionText.Height -= TextGapTop + TextGapBottom;
+
+            Color colorText;
+            if (DockPane.IsActivated)
+                colorText = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveCaptionGradient.TextColor;
+            else
+                colorText = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveCaptionGradient.TextColor;
+
+            TextRenderer.DrawText(g, DockPane.CaptionText, TextFont, DrawHelper.RtlTransform(this, rectCaptionText), colorText, TextFormat);
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+			SetButtonsPosition();
+			base.OnLayout (levent);
+		}
+
+		protected override void OnRefreshChanges()
+		{
+			SetButtons();
+			Invalidate();
+		}
+
+		private bool CloseButtonEnabled
+		{
+			get	{	return (DockPane.ActiveContent != null)? DockPane.ActiveContent.DockHandler.CloseButton : false;	}
+		}
+
+        /// <summary>
+        /// Determines whether the close button is visible on the content
+        /// </summary>
+        private bool CloseButtonVisible
+        {
+            get { return (DockPane.ActiveContent != null) ? DockPane.ActiveContent.DockHandler.CloseButtonVisible : false; }
+        }
+
+		private bool ShouldShowAutoHideButton
+		{
+			get	{	return !DockPane.IsFloat;	}
+		}
+
+		private void SetButtons()
+		{
+			ButtonClose.Enabled = CloseButtonEnabled;
+            ButtonClose.Visible = CloseButtonVisible;
+			ButtonAutoHide.Visible = ShouldShowAutoHideButton;
+            ButtonOptions.Visible = HasTabPageContextMenu;
+            ButtonClose.RefreshChanges();
+            ButtonAutoHide.RefreshChanges();
+            ButtonOptions.RefreshChanges();
+			
+			SetButtonsPosition();
+		}
+
+		private void SetButtonsPosition()
+		{
+			// set the size and location for close and auto-hide buttons
+			Rectangle rectCaption = ClientRectangle;
+			int buttonWidth = ButtonClose.Image.Width;
+			int buttonHeight = ButtonClose.Image.Height;
+			int height = rectCaption.Height - ButtonGapTop - ButtonGapBottom;
+			if (buttonHeight < height)
+			{
+				buttonWidth = buttonWidth * (height / buttonHeight);
+				buttonHeight = height;
+			}
+			Size buttonSize = new Size(buttonWidth, buttonHeight);
+			int x = rectCaption.X + rectCaption.Width - 1 - ButtonGapRight - m_buttonClose.Width;
+			int y = rectCaption.Y + ButtonGapTop;
+			Point point = new Point(x, y);
+            ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));
+
+            // If the close button is not visible draw the auto hide button overtop.
+            // Otherwise it is drawn to the left of the close button.
+            if (CloseButtonVisible)
+			    point.Offset(-(buttonWidth + ButtonGapBetween), 0);
+            
+            ButtonAutoHide.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));
+            if (ShouldShowAutoHideButton)
+                point.Offset(-(buttonWidth + ButtonGapBetween), 0);
+            ButtonOptions.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));
+		}
+
+		private void Close_Click(object sender, EventArgs e)
+		{
+			DockPane.CloseActiveContent();
+		}
+
+		private void AutoHide_Click(object sender, EventArgs e)
+		{
+			DockPane.DockState = DockHelper.ToggleAutoHideState(DockPane.DockState);
+            if (DockHelper.IsDockStateAutoHide(DockPane.DockState))
+                DockPane.DockPanel.ActiveAutoHideContent = null;
+
+		}
+
+        private void Options_Click(object sender, EventArgs e)
+        {
+            ShowTabPageContextMenu(PointToClient(Control.MousePosition));
+        }
+
+        protected override void OnRightToLeftChanged(EventArgs e)
+        {
+            base.OnRightToLeftChanged(e);
+            PerformLayout();
+        }
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005DockPaneStrip.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005DockPaneStrip.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VS2005DockPaneStrip.cs	(revision 2645)
@@ -0,0 +1,1479 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+using System.ComponentModel;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	internal class VS2005DockPaneStrip : DockPaneStripBase
+	{
+        private class TabVS2005 : Tab
+        {
+            public TabVS2005(IDockContent content)
+                : base(content)
+            {
+            }
+
+            private int m_tabX;
+            public int TabX
+            {
+                get { return m_tabX; }
+                set { m_tabX = value; }
+            }
+
+            private int m_tabWidth;
+            public int TabWidth
+            {
+                get { return m_tabWidth; }
+                set { m_tabWidth = value; }
+            }
+
+            private int m_maxWidth;
+            public int MaxWidth
+            {
+                get { return m_maxWidth; }
+                set { m_maxWidth = value; }
+            }
+
+            private bool m_flag;
+            protected internal bool Flag
+            {
+                get { return m_flag; }
+                set { m_flag = value; }
+            }
+        }
+
+        protected internal override DockPaneStripBase.Tab CreateTab(IDockContent content)
+        {
+            return new TabVS2005(content);
+        }
+
+        private sealed class InertButton : InertButtonBase
+        {
+            private Bitmap m_image0, m_image1;
+
+            public InertButton(Bitmap image0, Bitmap image1)
+                : base()
+            {
+                m_image0 = image0;
+                m_image1 = image1;
+            }
+
+            private int m_imageCategory = 0;
+            public int ImageCategory
+            {
+                get { return m_imageCategory; }
+                set
+                {
+                    if (m_imageCategory == value)
+                        return;
+
+                    m_imageCategory = value;
+                    Invalidate();
+                }
+            }
+
+            public override Bitmap Image
+            {
+                get { return ImageCategory == 0 ? m_image0 : m_image1; }
+            }
+        }
+
+		#region consts
+        private const int _ToolWindowStripGapTop = 0;
+        private const int _ToolWindowStripGapBottom = 1;
+		private const int _ToolWindowStripGapLeft = 0;
+		private const int _ToolWindowStripGapRight = 0;
+		private const int _ToolWindowImageHeight = 16;
+		private const int _ToolWindowImageWidth = 16;
+		private const int _ToolWindowImageGapTop = 3;
+		private const int _ToolWindowImageGapBottom = 1;
+		private const int _ToolWindowImageGapLeft = 2;
+		private const int _ToolWindowImageGapRight = 0;
+		private const int _ToolWindowTextGapRight = 3;
+		private const int _ToolWindowTabSeperatorGapTop = 3;
+		private const int _ToolWindowTabSeperatorGapBottom = 3;
+
+        private const int _DocumentStripGapTop = 0;
+        private const int _DocumentStripGapBottom = 1;
+		private const int _DocumentTabMaxWidth = 200;
+		private const int _DocumentButtonGapTop = 4;
+		private const int _DocumentButtonGapBottom = 4;
+		private const int _DocumentButtonGapBetween = 0;
+		private const int _DocumentButtonGapRight = 3;
+		private const int _DocumentTabGapTop = 3;
+		private const int _DocumentTabGapLeft = 3;
+		private const int _DocumentTabGapRight = 3;
+        private const int _DocumentIconGapBottom = 2;
+		private const int _DocumentIconGapLeft = 8;
+        private const int _DocumentIconGapRight = 0;
+		private const int _DocumentIconHeight = 16;
+		private const int _DocumentIconWidth = 16;
+        private const int _DocumentTextGapRight = 3;
+		#endregion
+
+        private static Bitmap _imageButtonClose;
+        private static Bitmap ImageButtonClose
+        {
+            get
+            {
+                if (_imageButtonClose == null)
+                    _imageButtonClose = Resources.DockPane_Close;
+
+                return _imageButtonClose;
+            }
+        }
+
+        private InertButton m_buttonClose;
+        private InertButton ButtonClose
+        {
+            get
+            {
+                if (m_buttonClose == null)
+                {
+                    m_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose);
+                    m_toolTip.SetToolTip(m_buttonClose, ToolTipClose);
+                    m_buttonClose.Click += new EventHandler(Close_Click);
+                    Controls.Add(m_buttonClose);
+                }
+
+                return m_buttonClose;
+            }
+        }
+
+        private static Bitmap _imageButtonWindowList;
+        private static Bitmap ImageButtonWindowList
+        {
+            get
+            {
+                if (_imageButtonWindowList == null)
+                    _imageButtonWindowList = Resources.DockPane_Option;
+
+                return _imageButtonWindowList;
+            }
+        }
+
+        private static Bitmap _imageButtonWindowListOverflow;
+        private static Bitmap ImageButtonWindowListOverflow
+        {
+            get
+            {
+                if (_imageButtonWindowListOverflow == null)
+                    _imageButtonWindowListOverflow = Resources.DockPane_OptionOverflow;
+
+                return _imageButtonWindowListOverflow;
+            }
+        }
+
+        private InertButton m_buttonWindowList;
+        private InertButton ButtonWindowList
+        {
+            get
+            {
+                if (m_buttonWindowList == null)
+                {
+                    m_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow);
+                    m_toolTip.SetToolTip(m_buttonWindowList, ToolTipSelect);
+                    m_buttonWindowList.Click += new EventHandler(WindowList_Click);
+                    Controls.Add(m_buttonWindowList);
+                }
+
+                return m_buttonWindowList;
+            }
+        }
+
+        private static GraphicsPath GraphicsPath
+        {
+            get { return VS2005AutoHideStrip.GraphicsPath; }
+        }
+
+		private IContainer m_components;
+		private ToolTip m_toolTip;
+		private IContainer Components
+		{
+			get	{	return m_components;	}
+		}
+
+		#region Customizable Properties
+        private static int ToolWindowStripGapTop
+        {
+            get { return _ToolWindowStripGapTop; }
+        }
+
+        private static int ToolWindowStripGapBottom
+        {
+            get { return _ToolWindowStripGapBottom; }
+        }
+
+		private static int ToolWindowStripGapLeft
+		{
+			get	{	return _ToolWindowStripGapLeft;	}
+		}
+
+		private static int ToolWindowStripGapRight
+		{
+			get	{	return _ToolWindowStripGapRight;	}
+		}
+
+		private static int ToolWindowImageHeight
+		{
+			get	{	return _ToolWindowImageHeight;	}
+		}
+
+		private static int ToolWindowImageWidth
+		{
+			get	{	return _ToolWindowImageWidth;	}
+		}
+
+		private static int ToolWindowImageGapTop
+		{
+			get	{	return _ToolWindowImageGapTop;	}
+		}
+
+		private static int ToolWindowImageGapBottom
+		{
+			get	{	return _ToolWindowImageGapBottom;	}
+		}
+
+		private static int ToolWindowImageGapLeft
+		{
+			get	{	return _ToolWindowImageGapLeft;	}
+		}
+
+		private static int ToolWindowImageGapRight
+		{
+			get	{	return _ToolWindowImageGapRight;	}
+		}
+
+		private static int ToolWindowTextGapRight
+		{
+			get	{	return _ToolWindowTextGapRight;	}
+		}
+
+		private static int ToolWindowTabSeperatorGapTop
+		{
+			get	{	return _ToolWindowTabSeperatorGapTop;	}
+		}
+
+		private static int ToolWindowTabSeperatorGapBottom
+		{
+			get	{	return _ToolWindowTabSeperatorGapBottom;	}
+		}
+
+		private static string _toolTipClose;
+		private static string ToolTipClose
+		{
+			get
+			{	
+				if (_toolTipClose == null)
+					_toolTipClose = Strings.DockPaneStrip_ToolTipClose;
+				return _toolTipClose;
+			}
+		}
+
+		private static string _toolTipSelect;
+		private static string ToolTipSelect
+		{
+			get
+			{	
+				if (_toolTipSelect == null)
+					_toolTipSelect = Strings.DockPaneStrip_ToolTipWindowList;
+				return _toolTipSelect;
+			}
+		}
+
+		private TextFormatFlags ToolWindowTextFormat
+		{
+			get
+            {	
+                TextFormatFlags textFormat = TextFormatFlags.EndEllipsis |
+                    TextFormatFlags.HorizontalCenter |
+                    TextFormatFlags.SingleLine |
+                    TextFormatFlags.VerticalCenter;
+                if (RightToLeft == RightToLeft.Yes)
+                    return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right;
+                else
+                    return textFormat;
+            }
+		}
+
+        private static int DocumentStripGapTop
+        {
+            get { return _DocumentStripGapTop; }
+        }
+
+        private static int DocumentStripGapBottom
+        {
+            get { return _DocumentStripGapBottom; }
+        }
+
+		private TextFormatFlags DocumentTextFormat
+		{
+        	get
+            {
+                TextFormatFlags textFormat = TextFormatFlags.EndEllipsis |
+                    TextFormatFlags.SingleLine |
+                    TextFormatFlags.VerticalCenter |
+                    TextFormatFlags.HorizontalCenter;
+                if (RightToLeft == RightToLeft.Yes)
+                    return textFormat | TextFormatFlags.RightToLeft;
+                else
+                    return textFormat;
+            }
+		}
+
+		private static int DocumentTabMaxWidth
+		{
+			get	{	return _DocumentTabMaxWidth;	}
+		}
+
+		private static int DocumentButtonGapTop
+		{
+			get	{	return _DocumentButtonGapTop;	}
+		}
+
+		private static int DocumentButtonGapBottom
+		{
+			get	{	return _DocumentButtonGapBottom;	}
+		}
+
+		private static int DocumentButtonGapBetween
+		{
+			get	{	return _DocumentButtonGapBetween;	}
+		}
+
+		private static int DocumentButtonGapRight
+		{
+			get	{	return _DocumentButtonGapRight;	}
+		}
+
+		private static int DocumentTabGapTop
+		{
+			get	{	return _DocumentTabGapTop;	}
+		}
+
+		private static int DocumentTabGapLeft
+		{
+			get	{	return _DocumentTabGapLeft;	}
+		}
+
+		private static int DocumentTabGapRight
+		{
+			get	{	return _DocumentTabGapRight;	}
+		}
+
+        private static int DocumentIconGapBottom
+        {
+            get { return _DocumentIconGapBottom; }
+        }
+
+		private static int DocumentIconGapLeft
+		{
+            get { return _DocumentIconGapLeft; }
+		}
+
+        private static int DocumentIconGapRight
+        {
+            get { return _DocumentIconGapRight; }
+        }
+
+		private static int DocumentIconWidth
+		{
+			get	{	return _DocumentIconWidth;	}
+		}
+
+		private static int DocumentIconHeight
+		{
+			get	{	return _DocumentIconHeight;	}
+		}
+
+        private static int DocumentTextGapRight
+        {
+            get { return _DocumentTextGapRight; }
+        }
+
+		private static Pen PenToolWindowTabBorder
+		{
+			get	{	return SystemPens.GrayText;	}
+		}
+
+        private static Pen PenDocumentTabActiveBorder
+        {
+            get { return SystemPens.ControlDarkDark; }
+        }
+
+        private static Pen PenDocumentTabInactiveBorder
+        {
+            get { return SystemPens.GrayText; }
+        }
+		#endregion
+
+		public VS2005DockPaneStrip(DockPane pane) : base(pane)
+		{
+			SetStyle(ControlStyles.ResizeRedraw |
+                ControlStyles.UserPaint |
+                ControlStyles.AllPaintingInWmPaint |
+                ControlStyles.OptimizedDoubleBuffer, true);
+
+			SuspendLayout();
+
+			m_components = new Container();
+			m_toolTip = new ToolTip(Components);
+            m_selectMenu = new ContextMenuStrip(Components);
+
+			ResumeLayout();
+		}
+
+		protected override void Dispose(bool disposing)
+		{
+            if (disposing)
+            {
+                Components.Dispose();
+                if (m_boldFont != null)
+                {
+                    m_boldFont.Dispose();
+                    m_boldFont = null;
+                }
+            }
+			base.Dispose (disposing);
+		}
+
+        private static Font TextFont
+        {
+            get { return SystemInformation.MenuFont; }
+        }
+
+        private Font m_font;
+        private Font m_boldFont;
+        private Font BoldFont
+        {
+            get
+            {
+                if (IsDisposed)
+                    return null;
+
+                if (m_boldFont == null)
+                {
+                    m_font = TextFont;
+                    m_boldFont = new Font(TextFont, FontStyle.Bold);
+                }
+                else if (m_font != TextFont)
+                {
+                    m_boldFont.Dispose();
+                    m_font = TextFont;
+                    m_boldFont = new Font(TextFont, FontStyle.Bold);
+                }
+
+                return m_boldFont;
+            }
+        }
+
+        private int m_startDisplayingTab = 0;
+        private int StartDisplayingTab
+        {
+            get { return m_startDisplayingTab; }
+            set
+            {
+                m_startDisplayingTab = value;
+                Invalidate();
+            }
+        }
+
+        private int m_endDisplayingTab = 0;
+        private int EndDisplayingTab
+        {
+            get { return m_endDisplayingTab; }
+            set { m_endDisplayingTab = value; }
+        }
+
+        private int m_firstDisplayingTab = 0;
+        private int FirstDisplayingTab
+        {
+            get { return m_firstDisplayingTab; }
+            set { m_firstDisplayingTab = value; }
+        }
+
+        private bool m_documentTabsOverflow = false;
+        private bool DocumentTabsOverflow
+        {
+            set
+            {
+                if (m_documentTabsOverflow == value)
+                    return;
+
+                m_documentTabsOverflow = value;
+                if (value)
+                    ButtonWindowList.ImageCategory = 1;
+                else
+                    ButtonWindowList.ImageCategory = 0;
+            }
+        }
+
+		protected internal override int MeasureHeight()
+		{
+			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+				return MeasureHeight_ToolWindow();
+			else
+				return MeasureHeight_Document();
+		}
+
+		private int MeasureHeight_ToolWindow()
+		{
+			if (DockPane.IsAutoHide || Tabs.Count <= 1)
+				return 0;
+
+            int height = Math.Max(TextFont.Height, ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom)
+                + ToolWindowStripGapTop + ToolWindowStripGapBottom;
+
+			return height;
+		}
+
+		private int MeasureHeight_Document()
+		{
+			int height = Math.Max(TextFont.Height + DocumentTabGapTop,
+				ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom)
+                + DocumentStripGapBottom + DocumentStripGapTop;
+
+			return height;
+		}
+
+		protected override void OnPaint(PaintEventArgs e)
+		{
+            Rectangle rect = TabsRectangle;
+
+            if (Appearance == DockPane.AppearanceStyle.Document)
+            {
+                rect.X -= DocumentTabGapLeft;
+
+                // Add these values back in so that the DockStrip color is drawn
+                // beneath the close button and window list button.
+                rect.Width += DocumentTabGapLeft +
+                    DocumentTabGapRight +
+                    DocumentButtonGapRight +
+                    ButtonClose.Width +
+                    ButtonWindowList.Width;
+
+                // It is possible depending on the DockPanel DocumentStyle to have
+                // a Document without a DockStrip.
+                if (rect.Width > 0 && rect.Height > 0)
+                {
+                    Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.StartColor;
+                    Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.EndColor;
+                    LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.DockStripGradient.LinearGradientMode;
+                    using (LinearGradientBrush brush = new LinearGradientBrush(rect, startColor, endColor, gradientMode))
+                    {
+                        e.Graphics.FillRectangle(brush, rect);
+                    }
+                }
+            }
+            else
+            {
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.DockStripGradient.LinearGradientMode;
+                using (LinearGradientBrush brush = new LinearGradientBrush(rect, startColor, endColor, gradientMode))
+                {
+                    e.Graphics.FillRectangle(brush, rect);
+                }
+            }
+			base.OnPaint (e);
+			CalculateTabs();
+            if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null)
+            {
+                if (EnsureDocumentTabVisible(DockPane.ActiveContent, false))
+                    CalculateTabs();
+            }
+
+			DrawTabStrip(e.Graphics);
+		}
+
+		protected override void OnRefreshChanges()
+		{
+			SetInertButtons();
+			Invalidate();
+		}
+
+		protected internal override GraphicsPath GetOutline(int index)
+		{
+
+            if (Appearance == DockPane.AppearanceStyle.Document)
+                return GetOutline_Document(index);
+            else
+                return GetOutline_ToolWindow(index);
+
+		}
+
+        private GraphicsPath GetOutline_Document(int index)
+        {
+            Rectangle rectTab = GetTabRectangle(index);
+            rectTab.X -= rectTab.Height / 2;
+            rectTab.Intersect(TabsRectangle);
+            rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab));
+            Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle);
+
+            GraphicsPath path = new GraphicsPath();
+            GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true);
+            path.AddPath(pathTab, true);
+
+            if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+            {
+                path.AddLine(rectTab.Right, rectTab.Top, rectPaneClient.Right, rectTab.Top);
+                path.AddLine(rectPaneClient.Right, rectTab.Top, rectPaneClient.Right, rectPaneClient.Top);
+                path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Left, rectPaneClient.Top);
+                path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Left, rectTab.Top);
+                path.AddLine(rectPaneClient.Left, rectTab.Top, rectTab.Right, rectTab.Top);
+            }
+            else
+            {
+                path.AddLine(rectTab.Right, rectTab.Bottom, rectPaneClient.Right, rectTab.Bottom);
+                path.AddLine(rectPaneClient.Right, rectTab.Bottom, rectPaneClient.Right, rectPaneClient.Bottom);
+                path.AddLine(rectPaneClient.Right, rectPaneClient.Bottom, rectPaneClient.Left, rectPaneClient.Bottom);
+                path.AddLine(rectPaneClient.Left, rectPaneClient.Bottom, rectPaneClient.Left, rectTab.Bottom);
+                path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom);
+            }
+            return path;
+        }
+
+        private GraphicsPath GetOutline_ToolWindow(int index)
+        {
+            Rectangle rectTab = GetTabRectangle(index);
+            rectTab.Intersect(TabsRectangle);
+            rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab));
+            int y = rectTab.Top;
+            Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle);
+
+            GraphicsPath path = new GraphicsPath();
+            GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true);
+            path.AddPath(pathTab, true);
+            path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top);
+            path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top);
+            path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Right, rectPaneClient.Top);
+            path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top);
+            path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top);
+            return path;
+        }
+
+		private void CalculateTabs()
+		{
+			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+				CalculateTabs_ToolWindow();
+			else
+				CalculateTabs_Document();
+		}
+
+		private void CalculateTabs_ToolWindow()
+		{
+			if (Tabs.Count <= 1 || DockPane.IsAutoHide)
+				return;
+
+			Rectangle rectTabStrip = TabStripRectangle;
+
+			// Calculate tab widths
+			int countTabs = Tabs.Count;
+            foreach (TabVS2005 tab in Tabs)
+            {
+                tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab));
+                tab.Flag = false;
+            }
+
+			// Set tab whose max width less than average width
+			bool anyWidthWithinAverage = true;
+			int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight;
+			int totalAllocatedWidth = 0;
+			int averageWidth = totalWidth / countTabs;
+			int remainedTabs = countTabs;
+			for (anyWidthWithinAverage=true; anyWidthWithinAverage && remainedTabs>0;)
+			{
+				anyWidthWithinAverage = false;
+				foreach (TabVS2005 tab in Tabs)
+				{
+					if (tab.Flag)
+						continue;
+
+					if (tab.MaxWidth <= averageWidth)
+					{
+						tab.Flag = true;
+						tab.TabWidth = tab.MaxWidth;
+						totalAllocatedWidth += tab.TabWidth;
+						anyWidthWithinAverage = true;
+						remainedTabs--;
+					}
+				}
+				if (remainedTabs != 0)
+					averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs;
+			}
+
+			// If any tab width not set yet, set it to the average width
+			if (remainedTabs > 0)
+			{
+				int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs);
+				foreach (TabVS2005 tab in Tabs)
+				{
+					if (tab.Flag)
+						continue;
+
+					tab.Flag = true;
+					if (roundUpWidth > 0)
+					{
+						tab.TabWidth = averageWidth + 1;
+						roundUpWidth --;
+					}
+					else
+						tab.TabWidth = averageWidth;
+				}
+			}
+
+			// Set the X position of the tabs
+			int x = rectTabStrip.X + ToolWindowStripGapLeft;
+			foreach (TabVS2005 tab in Tabs)
+			{
+				tab.TabX = x;
+				x += tab.TabWidth;
+			}
+		}
+
+        private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index)
+        {
+            bool overflow = false;
+
+            TabVS2005 tab = Tabs[index] as TabVS2005;
+            tab.MaxWidth = GetMaxTabWidth(index);
+            int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth);
+            if (x + width < rectTabStrip.Right || index == StartDisplayingTab)
+            {
+                tab.TabX = x;
+                tab.TabWidth = width;
+                EndDisplayingTab = index;
+            }
+            else
+            {
+                tab.TabX = 0;
+                tab.TabWidth = 0;
+                overflow = true;
+            }
+            x += width;
+
+            return overflow;
+        }
+
+        /// <summary>
+        /// Calculate which tabs are displayed and in what order.
+        /// </summary>
+		private void CalculateTabs_Document()
+		{
+            if (m_startDisplayingTab >= Tabs.Count)
+                m_startDisplayingTab = 0;
+
+            Rectangle rectTabStrip = TabsRectangle;
+
+			int x = rectTabStrip.X + rectTabStrip.Height / 2;
+            bool overflow = false;
+
+            // Originally all new documents that were considered overflow
+            // (not enough pane strip space to show all tabs) were added to
+            // the far left (assuming not right to left) and the tabs on the
+            // right were dropped from view. If StartDisplayingTab is not 0
+            // then we are dealing with making sure a specific tab is kept in focus.
+            if (m_startDisplayingTab > 0)
+            {
+                int tempX = x;
+                TabVS2005 tab = Tabs[m_startDisplayingTab] as TabVS2005;
+                tab.MaxWidth = GetMaxTabWidth(m_startDisplayingTab);
+                int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth);
+
+                // Add the active tab and tabs to the left
+                for (int i = StartDisplayingTab; i >= 0; i--)
+                    CalculateDocumentTab(rectTabStrip, ref tempX, i);
+
+                // Store which tab is the first one displayed so that it
+                // will be drawn correctly (without part of the tab cut off)
+                FirstDisplayingTab = EndDisplayingTab;
+
+                tempX = x; // Reset X location because we are starting over
+                
+                // Start with the first tab displayed - name is a little misleading.
+                // Loop through each tab and set its location. If there is not enough
+                // room for all of them overflow will be returned.
+                for (int i = EndDisplayingTab; i < Tabs.Count; i++)
+                    overflow = CalculateDocumentTab(rectTabStrip, ref tempX, i);
+
+                // If not all tabs are shown then we have an overflow.
+                if (FirstDisplayingTab != 0)
+                    overflow = true;
+            }
+            else
+            {
+                for (int i = StartDisplayingTab; i < Tabs.Count; i++)
+                    overflow = CalculateDocumentTab(rectTabStrip, ref x, i);
+                for (int i = 0; i < StartDisplayingTab; i++)
+                    overflow = CalculateDocumentTab(rectTabStrip, ref x, i);
+
+                FirstDisplayingTab = StartDisplayingTab;
+            }
+
+            if (!overflow)
+            {
+                m_startDisplayingTab = 0;
+                FirstDisplayingTab = 0;
+                x = rectTabStrip.X + rectTabStrip.Height / 2;
+                foreach (TabVS2005 tab in Tabs)
+                {
+                    tab.TabX = x;
+                    x += tab.TabWidth;
+                }
+            }
+            DocumentTabsOverflow = overflow;
+		}
+
+        protected internal override void EnsureTabVisible(IDockContent content)
+		{
+            if (Appearance != DockPane.AppearanceStyle.Document || !Tabs.Contains(content))
+                return;
+
+            CalculateTabs();
+            EnsureDocumentTabVisible(content, true);
+		}
+
+        private bool EnsureDocumentTabVisible(IDockContent content, bool repaint)
+        {
+            int index = Tabs.IndexOf(content);
+            TabVS2005 tab = Tabs[index] as TabVS2005;
+            if (tab.TabWidth != 0)
+                return false;
+
+            StartDisplayingTab = index;
+            if (repaint)
+                Invalidate();
+
+            return true;
+        }
+
+		private int GetMaxTabWidth(int index)
+		{
+			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+				return GetMaxTabWidth_ToolWindow(index);
+			else
+				return GetMaxTabWidth_Document(index);
+		}
+
+		private int GetMaxTabWidth_ToolWindow(int index)
+		{
+			IDockContent content = Tabs[index].Content;
+			Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont);
+			return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft
+				+ ToolWindowImageGapRight + ToolWindowTextGapRight;
+		}
+
+		private int GetMaxTabWidth_Document(int index)
+		{
+			IDockContent content = Tabs[index].Content;
+
+            int height = GetTabRectangle_Document(index).Height;
+
+            Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat);
+
+			if (DockPane.DockPanel.ShowDocumentIcon)
+				return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight + DocumentTextGapRight;
+			else
+				return sizeText.Width + DocumentIconGapLeft + DocumentTextGapRight;
+		}
+
+		private void DrawTabStrip(Graphics g)
+		{
+			if (Appearance == DockPane.AppearanceStyle.Document)
+				DrawTabStrip_Document(g);
+			else
+				DrawTabStrip_ToolWindow(g);
+		}
+
+		private void DrawTabStrip_Document(Graphics g)
+		{
+			int count = Tabs.Count;
+			if (count == 0)
+				return;
+
+			Rectangle rectTabStrip = TabStripRectangle;
+
+            // Draw the tabs
+			Rectangle rectTabOnly = TabsRectangle;
+			Rectangle rectTab = Rectangle.Empty;
+            TabVS2005 tabActive = null;
+			g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly));
+			for (int i=0; i<count; i++)
+			{
+				rectTab = GetTabRectangle(i);
+                if (Tabs[i].Content == DockPane.ActiveContent)
+                {
+                    tabActive = Tabs[i] as TabVS2005;
+                    continue;
+                }
+				if (rectTab.IntersectsWith(rectTabOnly))
+					DrawTab(g, Tabs[i] as TabVS2005, rectTab);
+			}
+
+            g.SetClip(rectTabStrip);
+
+            if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Top + 1,
+                	rectTabStrip.Right, rectTabStrip.Top + 1);
+            else
+                g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Bottom - 1,
+                    rectTabStrip.Right, rectTabStrip.Bottom - 1);
+
+            g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly));
+            if (tabActive != null)
+            {
+                rectTab = GetTabRectangle(Tabs.IndexOf(tabActive));
+                if (rectTab.IntersectsWith(rectTabOnly))
+                    DrawTab(g, tabActive, rectTab);
+            }
+		}
+
+		private void DrawTabStrip_ToolWindow(Graphics g)
+		{
+			Rectangle rectTabStrip = TabStripRectangle;
+
+			g.DrawLine(PenToolWindowTabBorder, rectTabStrip.Left, rectTabStrip.Top,
+				rectTabStrip.Right, rectTabStrip.Top);
+
+			for (int i=0; i<Tabs.Count; i++)
+				DrawTab(g, Tabs[i] as TabVS2005, GetTabRectangle(i));
+		}
+
+		private Rectangle GetTabRectangle(int index)
+		{
+			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+				return GetTabRectangle_ToolWindow(index);
+			else
+				return GetTabRectangle_Document(index);
+		}
+
+		private Rectangle GetTabRectangle_ToolWindow(int index)
+		{
+			Rectangle rectTabStrip = TabStripRectangle;
+
+			TabVS2005 tab = (TabVS2005)(Tabs[index]);
+			return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height);
+		}
+
+		private Rectangle GetTabRectangle_Document(int index)
+		{
+			Rectangle rectTabStrip = TabStripRectangle;
+			TabVS2005 tab = (TabVS2005)Tabs[index];
+
+            Rectangle rect = new Rectangle();
+            rect.X = tab.TabX;
+            rect.Width = tab.TabWidth;
+            rect.Height = rectTabStrip.Height - DocumentTabGapTop;
+
+            if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                rect.Y = rectTabStrip.Y + DocumentStripGapBottom;
+            else
+                rect.Y = rectTabStrip.Y + DocumentTabGapTop;
+
+			return rect;
+		}
+
+        private void DrawTab(Graphics g, TabVS2005 tab, Rectangle rect)
+		{
+			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+				DrawTab_ToolWindow(g, tab, rect);
+			else
+				DrawTab_Document(g, tab, rect);
+		}
+
+        private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen)
+        {
+            if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+                return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen);
+            else
+                return GetTabOutline_Document(tab, rtlTransform, toScreen, false);
+        }
+
+        private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen)
+        {
+            Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab));
+            if (rtlTransform)
+                rect = DrawHelper.RtlTransform(this, rect);
+            if (toScreen)
+                rect = RectangleToScreen(rect);
+
+            DrawHelper.GetRoundedCornerTab(GraphicsPath, rect, false);
+            return GraphicsPath;
+        }
+
+        private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full)
+        {
+            int curveSize = 6;
+
+            GraphicsPath.Reset();
+            Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab));
+            if (rtlTransform)
+                rect = DrawHelper.RtlTransform(this, rect);
+            if (toScreen)
+                rect = RectangleToScreen(rect);
+
+            // Draws the full angle piece for active content (or first tab)
+            if (tab.Content == DockPane.ActiveContent || full || Tabs.IndexOf(tab) == FirstDisplayingTab)
+            {
+                if (RightToLeft == RightToLeft.Yes)
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    {
+                        // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top.
+                        // It is not needed so it has been commented out.
+                        //GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom);
+                        GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Top, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2);
+                    }
+                    else
+                    {
+                        GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom);
+                        GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Bottom, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2);
+                    }
+                }
+                else
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    {
+                        // For some reason the next line draws a line that is not hidden like it is when drawing the tab strip on top.
+                        // It is not needed so it has been commented out.
+                        //GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left - rect.Height / 2, rect.Top);
+                        GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Top, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2);
+                    }
+                    else
+                    {
+                        GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left - rect.Height / 2, rect.Bottom);
+                        GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Bottom, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2);
+                    }
+                }
+            }
+            // Draws the partial angle for non-active content
+            else
+            {
+                if (RightToLeft == RightToLeft.Yes)
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    {
+                        GraphicsPath.AddLine(rect.Right, rect.Top, rect.Right, rect.Top + rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Bottom - curveSize / 2);
+                    }
+                    else
+                    {
+                        GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right, rect.Bottom - rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2);
+                    }
+                }
+                else
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    {
+                        GraphicsPath.AddLine(rect.Left, rect.Top, rect.Left, rect.Top + rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Bottom - curveSize / 2);
+                    }
+                    else
+                    {
+                        GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, rect.Bottom - rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, rect.Top + curveSize / 2);
+                    }
+                }
+            }
+
+            if (RightToLeft == RightToLeft.Yes)
+            {
+                if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                {
+                    // Draws the bottom horizontal line (short side)
+                    GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Bottom, rect.Left + curveSize / 2, rect.Bottom);
+
+                    // Drawing the rounded corner is not necessary. The path is automatically connected
+                    //GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90);
+                }
+                else
+                {
+                    // Draws the bottom horizontal line (short side)
+                    GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Top, rect.Left + curveSize / 2, rect.Top);
+                    GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90);
+                }
+            }
+            else
+            {
+                if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                {
+                    // Draws the bottom horizontal line (short side)
+                    GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Bottom, rect.Right - curveSize / 2, rect.Bottom);
+
+                    // Drawing the rounded corner is not necessary. The path is automatically connected
+                    //GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Bottom, curveSize, curveSize), 90, -90);
+                }
+                else
+                {
+                    // Draws the top horizontal line (short side)
+                    GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top);
+
+                    // Draws the rounded corner oppposite the angled side
+                    GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90);
+                }
+            }
+
+            if (Tabs.IndexOf(tab) != EndDisplayingTab &&
+                (Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent)
+                && !full)
+            {
+                if (RightToLeft == RightToLeft.Yes)
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    {
+                        GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Bottom - rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2, rect.Top);
+                    }
+                    else
+                    {
+                        GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Top + rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2, rect.Bottom);
+                    }
+                }
+                else
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                    {
+                        GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Bottom - rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2, rect.Top);
+                    }
+                    else
+                    {
+                        GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Top + rect.Height / 2);
+                        GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2, rect.Bottom);
+                    }
+                }
+            }
+            else
+            {
+                // Draw the vertical line opposite the angled side
+                if (RightToLeft == RightToLeft.Yes)
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                        GraphicsPath.AddLine(rect.Left, rect.Bottom - curveSize / 2, rect.Left, rect.Top);
+                    else
+                        GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Bottom);
+                }
+                else
+                {
+                    if (DockPane.DockPanel.DocumentTabStripLocation == DocumentTabStripLocation.Bottom)
+                        GraphicsPath.AddLine(rect.Right, rect.Bottom - curveSize / 2, rect.Right, rect.Top);
+                    else
+                        GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom);
+                }
+            }
+
+            return GraphicsPath;
+        }
+
+		private void DrawTab_ToolWindow(Graphics g, TabVS2005 tab, Rectangle rect)
+		{
+			Rectangle rectIcon = new Rectangle(
+				rect.X + ToolWindowImageGapLeft,
+				rect.Y + rect.Height - 1 - ToolWindowImageGapBottom - ToolWindowImageHeight,
+				ToolWindowImageWidth, ToolWindowImageHeight);
+			Rectangle rectText = rectIcon;
+			rectText.X += rectIcon.Width + ToolWindowImageGapRight;
+			rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft - 
+				ToolWindowImageGapRight - ToolWindowTextGapRight;
+
+            Rectangle rectTab = DrawHelper.RtlTransform(this, rect);
+            rectText = DrawHelper.RtlTransform(this, rectText);
+            rectIcon = DrawHelper.RtlTransform(this, rectIcon);
+            GraphicsPath path = GetTabOutline(tab, true, false);
+			if (DockPane.ActiveContent == tab.Content)
+			{
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.LinearGradientMode;
+				g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path);
+                g.DrawPath(PenToolWindowTabBorder, path);
+
+                Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.ActiveTabGradient.TextColor;
+                TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat);
+			}
+			else
+			{
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.LinearGradientMode;
+                g.FillPath(new LinearGradientBrush(rectTab, startColor, endColor, gradientMode), path);
+
+                if (Tabs.IndexOf(DockPane.ActiveContent) != Tabs.IndexOf(tab) + 1)
+                {
+                    Point pt1 = new Point(rect.Right, rect.Top + ToolWindowTabSeperatorGapTop);
+                    Point pt2 = new Point(rect.Right, rect.Bottom - ToolWindowTabSeperatorGapBottom); 
+                    g.DrawLine(PenToolWindowTabBorder, DrawHelper.RtlTransform(this, pt1), DrawHelper.RtlTransform(this, pt2));
+                }
+
+                Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.ToolWindowGradient.InactiveTabGradient.TextColor;
+                TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, ToolWindowTextFormat);
+			}
+
+			if (rectTab.Contains(rectIcon))
+				g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon);
+		}
+
+		private void DrawTab_Document(Graphics g, TabVS2005 tab, Rectangle rect)
+		{
+            if (tab.TabWidth == 0)
+                return;
+
+            Rectangle rectIcon = new Rectangle(
+                rect.X + DocumentIconGapLeft,
+                rect.Y + rect.Height - 1 - DocumentIconGapBottom - DocumentIconHeight,
+                DocumentIconWidth, DocumentIconHeight);
+            Rectangle rectText = rectIcon;
+            if (DockPane.DockPanel.ShowDocumentIcon)
+            {
+                rectText.X += rectIcon.Width + DocumentIconGapRight;
+                rectText.Y = rect.Y;
+                rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft -
+                    DocumentIconGapRight - DocumentTextGapRight;
+                rectText.Height = rect.Height;
+            }
+            else
+                rectText.Width = rect.Width - DocumentIconGapLeft - DocumentTextGapRight;
+
+            Rectangle rectTab = DrawHelper.RtlTransform(this, rect);
+            Rectangle rectBack = DrawHelper.RtlTransform(this, rect);
+            rectBack.Width += rect.X;
+            rectBack.X = 0;
+
+            rectText = DrawHelper.RtlTransform(this, rectText);
+            rectIcon = DrawHelper.RtlTransform(this, rectIcon);
+            GraphicsPath path = GetTabOutline(tab, true, false);
+            if (DockPane.ActiveContent == tab.Content)
+            {
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.LinearGradientMode;
+                g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path);
+                g.DrawPath(PenDocumentTabActiveBorder, path);
+
+                Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.ActiveTabGradient.TextColor;
+                if (DockPane.IsActiveDocumentPane)
+                    TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, BoldFont, rectText, textColor, DocumentTextFormat);
+                else
+                    TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat);
+            }
+            else
+            {
+                Color startColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.StartColor;
+                Color endColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.EndColor;
+                LinearGradientMode gradientMode = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.LinearGradientMode;
+                g.FillPath(new LinearGradientBrush(rectBack, startColor, endColor, gradientMode), path);
+                g.DrawPath(PenDocumentTabInactiveBorder, path);
+
+                Color textColor = DockPane.DockPanel.Skin.DockPaneStripSkin.DocumentGradient.InactiveTabGradient.TextColor;
+                TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, textColor, DocumentTextFormat);
+            }
+
+            if (rectTab.Contains(rectIcon) && DockPane.DockPanel.ShowDocumentIcon)
+                g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon);
+        }
+
+        private Rectangle TabStripRectangle
+        {
+            get
+            {
+                if (Appearance == DockPane.AppearanceStyle.Document)
+                    return TabStripRectangle_Document;
+                else
+                    return TabStripRectangle_ToolWindow;
+            }
+        }
+
+        private Rectangle TabStripRectangle_ToolWindow
+        {
+            get
+            {
+                Rectangle rect = ClientRectangle;
+                return new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom);
+            }
+        }
+
+        private Rectangle TabStripRectangle_Document
+        {
+            get
+            {
+                Rectangle rect = ClientRectangle;
+                return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, rect.Height - DocumentStripGapTop - ToolWindowStripGapBottom);
+            }
+        }
+
+		private Rectangle TabsRectangle
+		{
+			get	
+			{
+				if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+					return TabStripRectangle;
+
+				Rectangle rectWindow = TabStripRectangle;
+				int x = rectWindow.X;
+				int y = rectWindow.Y;
+				int width = rectWindow.Width;
+				int height = rectWindow.Height;
+
+				x += DocumentTabGapLeft;
+				width -= DocumentTabGapLeft + 
+						DocumentTabGapRight +
+						DocumentButtonGapRight +
+						ButtonClose.Width +
+						ButtonWindowList.Width +
+						2 * DocumentButtonGapBetween;
+
+				return new Rectangle(x, y, width, height);
+			}
+		}
+
+        private ContextMenuStrip m_selectMenu;
+        private ContextMenuStrip SelectMenu
+        {
+            get { return m_selectMenu; }
+        }
+
+        private void WindowList_Click(object sender, EventArgs e)
+        {
+            int x = 0;
+            int y = ButtonWindowList.Location.Y + ButtonWindowList.Height;
+
+            SelectMenu.Items.Clear();
+            foreach (TabVS2005 tab in Tabs)
+            {
+                IDockContent content = tab.Content;
+                ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap());
+                item.Tag = tab.Content;
+                item.Click += new EventHandler(ContextMenuItem_Click);
+            }
+            SelectMenu.Show(ButtonWindowList, x, y);
+        }
+
+        private void ContextMenuItem_Click(object sender, EventArgs e)
+        {
+            ToolStripMenuItem item = sender as ToolStripMenuItem;
+            if (item != null)
+            {
+                IDockContent content = (IDockContent)item.Tag;
+                DockPane.ActiveContent = content;
+            }
+		}
+	
+		private void SetInertButtons()
+		{
+            if (Appearance == DockPane.AppearanceStyle.ToolWindow)
+            {
+                if (m_buttonClose != null)
+                    m_buttonClose.Left = -m_buttonClose.Width;
+
+                if (m_buttonWindowList != null)
+                    m_buttonWindowList.Left = -m_buttonWindowList.Width;
+            }
+            else
+            {
+                bool showCloseButton = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton;
+                ButtonClose.Enabled = showCloseButton;
+                ButtonClose.Visible = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButtonVisible;
+                ButtonClose.RefreshChanges();
+                ButtonWindowList.RefreshChanges();
+            }
+		}
+
+		protected override void OnLayout(LayoutEventArgs levent)
+		{
+            if (Appearance != DockPane.AppearanceStyle.Document)
+            {
+                base.OnLayout(levent);
+                return;
+            }
+
+			Rectangle rectTabStrip = TabStripRectangle;
+
+            // Set position and size of the buttons
+			int buttonWidth = ButtonClose.Image.Width;
+			int buttonHeight = ButtonClose.Image.Height;
+            int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom;
+			if (buttonHeight < height)
+			{
+				buttonWidth = buttonWidth * (height / buttonHeight);
+				buttonHeight = height;
+			}
+			Size buttonSize = new Size(buttonWidth, buttonHeight);
+
+			int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft
+				- DocumentButtonGapRight - buttonWidth;
+			int y = rectTabStrip.Y + DocumentButtonGapTop;
+            Point point = new Point(x, y);
+			ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));
+            
+            // If the close button is not visible draw the window list button overtop.
+            // Otherwise it is drawn to the left of the close button.
+            if (ButtonClose.Visible)
+			    point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0);
+            
+            ButtonWindowList.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));
+
+			OnRefreshChanges();
+
+			base.OnLayout (levent);
+		}
+
+		private void Close_Click(object sender, EventArgs e)
+		{
+			DockPane.CloseActiveContent();
+		}
+
+		protected internal override int HitTest(Point ptMouse)
+		{
+			Rectangle rectTabStrip = TabsRectangle;
+            if (!TabsRectangle.Contains(ptMouse))
+                return -1;
+
+            foreach (Tab tab in Tabs)
+            {
+                GraphicsPath path = GetTabOutline(tab, true, false);
+                if (path.IsVisible(ptMouse))
+                    return Tabs.IndexOf(tab);
+            }
+            return -1;
+		}
+
+		protected override void OnMouseHover(EventArgs e)
+		{
+			int index = HitTest(PointToClient(Control.MousePosition));
+			string toolTip = string.Empty;
+
+			base.OnMouseHover(e);
+
+            if (index != -1)
+			{
+                TabVS2005 tab = Tabs[index] as TabVS2005;
+                if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText))
+                    toolTip = tab.Content.DockHandler.ToolTipText;
+                else if (tab.MaxWidth > tab.TabWidth)
+                    toolTip = tab.Content.DockHandler.TabText;
+			}
+
+			if (m_toolTip.GetToolTip(this) != toolTip)
+			{
+				m_toolTip.Active = false;
+				m_toolTip.SetToolTip(this, toolTip);
+				m_toolTip.Active = true;
+			}
+
+            // requires further tracking of mouse hover behavior,
+            ResetMouseEventArgs();
+		}
+
+        protected override void OnRightToLeftChanged(EventArgs e)
+        {
+            base.OnRightToLeftChanged(e);
+            PerformLayout();
+        }
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VisibleNestedPaneCollection.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VisibleNestedPaneCollection.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/VisibleNestedPaneCollection.cs	(revision 2645)
@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+	public sealed class VisibleNestedPaneCollection : ReadOnlyCollection<DockPane>
+	{
+		private NestedPaneCollection m_nestedPanes;
+
+        internal VisibleNestedPaneCollection(NestedPaneCollection nestedPanes)
+            : base(new List<DockPane>())
+        {
+            m_nestedPanes = nestedPanes;
+        }
+
+		public NestedPaneCollection NestedPanes
+		{
+			get	{	return m_nestedPanes;	}
+		}
+
+		public INestedPanesContainer Container
+		{
+			get	{	return NestedPanes.Container;	}
+		}
+
+		public DockState DockState
+		{
+			get	{	return NestedPanes.DockState;	}
+		}
+
+		public bool IsFloat
+		{
+			get	{	return NestedPanes.IsFloat;	}
+		}
+
+		internal void Refresh()
+		{
+			Items.Clear();
+			for (int i=0; i<NestedPanes.Count; i++)
+			{
+				DockPane pane = NestedPanes[i];
+				NestedDockingStatus status = pane.NestedDockingStatus;
+				status.SetDisplayingStatus(true, status.PreviousPane, status.Alignment, status.Proportion);
+				Items.Add(pane);
+			}
+
+			foreach (DockPane pane in NestedPanes)
+				if (pane.DockState != DockState || pane.IsHidden)
+				{
+					pane.Bounds = Rectangle.Empty;
+					pane.SplitterBounds = Rectangle.Empty;
+					Remove(pane);
+				}
+
+			CalculateBounds();
+
+			foreach (DockPane pane in this)
+			{
+				NestedDockingStatus status = pane.NestedDockingStatus;
+				pane.Bounds = status.PaneBounds;
+				pane.SplitterBounds = status.SplitterBounds;
+				pane.SplitterAlignment = status.Alignment;
+			}
+		}
+
+		private void Remove(DockPane pane)
+		{
+			if (!Contains(pane))
+				return;
+
+			NestedDockingStatus statusPane = pane.NestedDockingStatus;
+			DockPane lastNestedPane = null;
+			for (int i=Count - 1; i> IndexOf(pane); i--)
+			{
+				if (this[i].NestedDockingStatus.PreviousPane == pane)
+				{
+					lastNestedPane = this[i];
+					break;
+				}
+			}
+
+			if (lastNestedPane != null)
+			{
+				int indexLastNestedPane = IndexOf(lastNestedPane);
+				Items.Remove(lastNestedPane);
+				Items[IndexOf(pane)] = lastNestedPane;
+				NestedDockingStatus lastNestedDock = lastNestedPane.NestedDockingStatus;
+				lastNestedDock.SetDisplayingStatus(true, statusPane.DisplayingPreviousPane, statusPane.DisplayingAlignment, statusPane.DisplayingProportion);
+				for (int i=indexLastNestedPane - 1; i>IndexOf(lastNestedPane); i--)
+				{
+					NestedDockingStatus status = this[i].NestedDockingStatus;
+					if (status.PreviousPane == pane)
+						status.SetDisplayingStatus(true, lastNestedPane, status.DisplayingAlignment, status.DisplayingProportion);
+				}
+			}
+			else
+				Items.Remove(pane);
+
+			statusPane.SetDisplayingStatus(false, null, DockAlignment.Left, 0.5);
+		}
+
+		private void CalculateBounds()
+		{
+			if (Count == 0)
+				return;
+
+			this[0].NestedDockingStatus.SetDisplayingBounds(Container.DisplayingRectangle, Container.DisplayingRectangle, Rectangle.Empty);
+
+			for (int i=1; i<Count; i++)
+			{
+				DockPane pane = this[i];
+				NestedDockingStatus status = pane.NestedDockingStatus;
+				DockPane prevPane = status.DisplayingPreviousPane;
+				NestedDockingStatus statusPrev = prevPane.NestedDockingStatus;
+
+				Rectangle rect = statusPrev.PaneBounds;
+				bool bVerticalSplitter = (status.DisplayingAlignment == DockAlignment.Left || status.DisplayingAlignment == DockAlignment.Right);
+
+				Rectangle rectThis = rect;
+				Rectangle rectPrev = rect;
+				Rectangle rectSplitter = rect;
+				if (status.DisplayingAlignment == DockAlignment.Left)
+				{
+					rectThis.Width = (int)((double)rect.Width * status.DisplayingProportion) - (Measures.SplitterSize / 2);
+					rectSplitter.X = rectThis.X + rectThis.Width;
+					rectSplitter.Width = Measures.SplitterSize;
+					rectPrev.X = rectSplitter.X + rectSplitter.Width;
+					rectPrev.Width = rect.Width - rectThis.Width - rectSplitter.Width;
+				}
+				else if (status.DisplayingAlignment == DockAlignment.Right)
+				{
+					rectPrev.Width = (rect.Width - (int)((double)rect.Width * status.DisplayingProportion)) - (Measures.SplitterSize / 2);
+					rectSplitter.X = rectPrev.X + rectPrev.Width;
+					rectSplitter.Width = Measures.SplitterSize;
+					rectThis.X = rectSplitter.X + rectSplitter.Width;
+					rectThis.Width = rect.Width - rectPrev.Width - rectSplitter.Width;
+				}
+				else if (status.DisplayingAlignment == DockAlignment.Top)
+				{
+					rectThis.Height = (int)((double)rect.Height * status.DisplayingProportion) - (Measures.SplitterSize / 2);
+					rectSplitter.Y = rectThis.Y + rectThis.Height;
+					rectSplitter.Height = Measures.SplitterSize;
+					rectPrev.Y = rectSplitter.Y + rectSplitter.Height;
+					rectPrev.Height = rect.Height - rectThis.Height - rectSplitter.Height;
+				}
+				else if (status.DisplayingAlignment == DockAlignment.Bottom)
+				{
+					rectPrev.Height = (rect.Height - (int)((double)rect.Height * status.DisplayingProportion)) - (Measures.SplitterSize / 2);
+					rectSplitter.Y = rectPrev.Y + rectPrev.Height;
+					rectSplitter.Height = Measures.SplitterSize;
+					rectThis.Y = rectSplitter.Y + rectSplitter.Height;
+					rectThis.Height = rect.Height - rectPrev.Height - rectSplitter.Height;
+				}
+				else
+					rectThis = Rectangle.Empty;
+
+				rectSplitter.Intersect(rect);
+				rectThis.Intersect(rect);
+				rectPrev.Intersect(rect);
+				status.SetDisplayingBounds(rect, rectThis, rectSplitter);
+				statusPrev.SetDisplayingBounds(statusPrev.LogicalBounds, rectPrev, statusPrev.SplitterBounds);
+			}
+		}
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Win32/Enums.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Win32/Enums.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Win32/Enums.cs	(revision 2645)
@@ -0,0 +1,369 @@
+using System;
+
+namespace WeifenLuo.WinFormsUI.Docking.Win32
+{
+	[Flags]
+	internal enum FlagsSetWindowPos : uint
+	{
+		SWP_NOSIZE          = 0x0001,
+		SWP_NOMOVE          = 0x0002,
+		SWP_NOZORDER        = 0x0004,
+		SWP_NOREDRAW        = 0x0008,
+		SWP_NOACTIVATE      = 0x0010,
+		SWP_FRAMECHANGED    = 0x0020,
+		SWP_SHOWWINDOW      = 0x0040,
+		SWP_HIDEWINDOW      = 0x0080,
+		SWP_NOCOPYBITS      = 0x0100,
+		SWP_NOOWNERZORDER   = 0x0200, 
+		SWP_NOSENDCHANGING  = 0x0400,
+		SWP_DRAWFRAME       = 0x0020,
+		SWP_NOREPOSITION    = 0x0200,
+		SWP_DEFERERASE      = 0x2000,
+		SWP_ASYNCWINDOWPOS  = 0x4000
+	}
+
+	internal enum ShowWindowStyles : short
+	{
+		SW_HIDE             = 0,
+		SW_SHOWNORMAL       = 1,
+		SW_NORMAL           = 1,
+		SW_SHOWMINIMIZED    = 2,
+		SW_SHOWMAXIMIZED    = 3,
+		SW_MAXIMIZE         = 3,
+		SW_SHOWNOACTIVATE   = 4,
+		SW_SHOW             = 5,
+		SW_MINIMIZE         = 6,
+		SW_SHOWMINNOACTIVE  = 7,
+		SW_SHOWNA           = 8,
+		SW_RESTORE          = 9,
+		SW_SHOWDEFAULT      = 10,
+		SW_FORCEMINIMIZE    = 11,
+		SW_MAX              = 11
+	}
+
+	internal enum WindowStyles : uint
+	{
+		WS_OVERLAPPED       = 0x00000000,
+		WS_POPUP            = 0x80000000,
+		WS_CHILD            = 0x40000000,
+		WS_MINIMIZE         = 0x20000000,
+		WS_VISIBLE          = 0x10000000,
+		WS_DISABLED         = 0x08000000,
+		WS_CLIPSIBLINGS     = 0x04000000,
+		WS_CLIPCHILDREN     = 0x02000000,
+		WS_MAXIMIZE         = 0x01000000,
+		WS_CAPTION          = 0x00C00000,
+		WS_BORDER           = 0x00800000,
+		WS_DLGFRAME         = 0x00400000,
+		WS_VSCROLL          = 0x00200000,
+		WS_HSCROLL          = 0x00100000,
+		WS_SYSMENU          = 0x00080000,
+		WS_THICKFRAME       = 0x00040000,
+		WS_GROUP            = 0x00020000,
+		WS_TABSTOP          = 0x00010000,
+		WS_MINIMIZEBOX      = 0x00020000,
+		WS_MAXIMIZEBOX      = 0x00010000,
+		WS_TILED            = 0x00000000,
+		WS_ICONIC           = 0x20000000,
+		WS_SIZEBOX          = 0x00040000,
+		WS_POPUPWINDOW      = 0x80880000,
+		WS_OVERLAPPEDWINDOW = 0x00CF0000,
+		WS_TILEDWINDOW      = 0x00CF0000,
+		WS_CHILDWINDOW      = 0x40000000
+	}
+
+	internal enum WindowExStyles
+	{
+		WS_EX_DLGMODALFRAME     = 0x00000001,
+		WS_EX_NOPARENTNOTIFY    = 0x00000004,
+		WS_EX_TOPMOST           = 0x00000008,
+		WS_EX_ACCEPTFILES       = 0x00000010,
+		WS_EX_TRANSPARENT       = 0x00000020,
+		WS_EX_MDICHILD          = 0x00000040,
+		WS_EX_TOOLWINDOW        = 0x00000080,
+		WS_EX_WINDOWEDGE        = 0x00000100,
+		WS_EX_CLIENTEDGE        = 0x00000200,
+		WS_EX_CONTEXTHELP       = 0x00000400,
+		WS_EX_RIGHT             = 0x00001000,
+		WS_EX_LEFT              = 0x00000000,
+		WS_EX_RTLREADING        = 0x00002000,
+		WS_EX_LTRREADING        = 0x00000000,
+		WS_EX_LEFTSCROLLBAR     = 0x00004000,
+		WS_EX_RIGHTSCROLLBAR    = 0x00000000,
+		WS_EX_CONTROLPARENT     = 0x00010000,
+		WS_EX_STATICEDGE        = 0x00020000,
+		WS_EX_APPWINDOW         = 0x00040000,
+		WS_EX_OVERLAPPEDWINDOW  = 0x00000300,
+		WS_EX_PALETTEWINDOW     = 0x00000188,
+		WS_EX_LAYERED			= 0x00080000
+	}
+
+	internal enum Msgs
+	{
+		WM_NULL                   = 0x0000,
+		WM_CREATE                 = 0x0001,
+		WM_DESTROY                = 0x0002,
+		WM_MOVE                   = 0x0003,
+		WM_SIZE                   = 0x0005,
+		WM_ACTIVATE               = 0x0006,
+		WM_SETFOCUS               = 0x0007,
+		WM_KILLFOCUS              = 0x0008,
+		WM_ENABLE                 = 0x000A,
+		WM_SETREDRAW              = 0x000B,
+		WM_SETTEXT                = 0x000C,
+		WM_GETTEXT                = 0x000D,
+		WM_GETTEXTLENGTH          = 0x000E,
+		WM_PAINT                  = 0x000F,
+		WM_CLOSE                  = 0x0010,
+		WM_QUERYENDSESSION        = 0x0011,
+		WM_QUIT                   = 0x0012,
+		WM_QUERYOPEN              = 0x0013,
+		WM_ERASEBKGND             = 0x0014,
+		WM_SYSCOLORCHANGE         = 0x0015,
+		WM_ENDSESSION             = 0x0016,
+		WM_SHOWWINDOW             = 0x0018,
+		WM_WININICHANGE           = 0x001A,
+		WM_SETTINGCHANGE          = 0x001A,
+		WM_DEVMODECHANGE          = 0x001B,
+		WM_ACTIVATEAPP            = 0x001C,
+		WM_FONTCHANGE             = 0x001D,
+		WM_TIMECHANGE             = 0x001E,
+		WM_CANCELMODE             = 0x001F,
+		WM_SETCURSOR              = 0x0020,
+		WM_MOUSEACTIVATE          = 0x0021,
+		WM_CHILDACTIVATE          = 0x0022,
+		WM_QUEUESYNC              = 0x0023,
+		WM_GETMINMAXINFO          = 0x0024,
+		WM_PAINTICON              = 0x0026,
+		WM_ICONERASEBKGND         = 0x0027,
+		WM_NEXTDLGCTL             = 0x0028,
+		WM_SPOOLERSTATUS          = 0x002A,
+		WM_DRAWITEM               = 0x002B,
+		WM_MEASUREITEM            = 0x002C,
+		WM_DELETEITEM             = 0x002D,
+		WM_VKEYTOITEM             = 0x002E,
+		WM_CHARTOITEM             = 0x002F,
+		WM_SETFONT                = 0x0030,
+		WM_GETFONT                = 0x0031,
+		WM_SETHOTKEY              = 0x0032,
+		WM_GETHOTKEY              = 0x0033,
+		WM_QUERYDRAGICON          = 0x0037,
+		WM_COMPAREITEM            = 0x0039,
+		WM_GETOBJECT              = 0x003D,
+		WM_COMPACTING             = 0x0041,
+		WM_COMMNOTIFY             = 0x0044 ,
+		WM_WINDOWPOSCHANGING      = 0x0046,
+		WM_WINDOWPOSCHANGED       = 0x0047,
+		WM_POWER                  = 0x0048,
+		WM_COPYDATA               = 0x004A,
+		WM_CANCELJOURNAL          = 0x004B,
+		WM_NOTIFY                 = 0x004E,
+		WM_INPUTLANGCHANGEREQUEST = 0x0050,
+		WM_INPUTLANGCHANGE        = 0x0051,
+		WM_TCARD                  = 0x0052,
+		WM_HELP                   = 0x0053,
+		WM_USERCHANGED            = 0x0054,
+		WM_NOTIFYFORMAT           = 0x0055,
+		WM_CONTEXTMENU            = 0x007B,
+		WM_STYLECHANGING          = 0x007C,
+		WM_STYLECHANGED           = 0x007D,
+		WM_DISPLAYCHANGE          = 0x007E,
+		WM_GETICON                = 0x007F,
+		WM_SETICON                = 0x0080,
+		WM_NCCREATE               = 0x0081,
+		WM_NCDESTROY              = 0x0082,
+		WM_NCCALCSIZE             = 0x0083,
+		WM_NCHITTEST              = 0x0084,
+		WM_NCPAINT                = 0x0085,
+		WM_NCACTIVATE             = 0x0086,
+		WM_GETDLGCODE             = 0x0087,
+		WM_SYNCPAINT              = 0x0088,
+		WM_NCMOUSEMOVE            = 0x00A0,
+		WM_NCLBUTTONDOWN          = 0x00A1,
+		WM_NCLBUTTONUP            = 0x00A2,
+		WM_NCLBUTTONDBLCLK        = 0x00A3,
+		WM_NCRBUTTONDOWN          = 0x00A4,
+		WM_NCRBUTTONUP            = 0x00A5,
+		WM_NCRBUTTONDBLCLK        = 0x00A6,
+		WM_NCMBUTTONDOWN          = 0x00A7,
+		WM_NCMBUTTONUP            = 0x00A8,
+		WM_NCMBUTTONDBLCLK        = 0x00A9,
+		WM_KEYDOWN                = 0x0100,
+		WM_KEYUP                  = 0x0101,
+		WM_CHAR                   = 0x0102,
+		WM_DEADCHAR               = 0x0103,
+		WM_SYSKEYDOWN             = 0x0104,
+		WM_SYSKEYUP               = 0x0105,
+		WM_SYSCHAR                = 0x0106,
+		WM_SYSDEADCHAR            = 0x0107,
+		WM_KEYLAST                = 0x0108,
+		WM_IME_STARTCOMPOSITION   = 0x010D,
+		WM_IME_ENDCOMPOSITION     = 0x010E,
+		WM_IME_COMPOSITION        = 0x010F,
+		WM_IME_KEYLAST            = 0x010F,
+		WM_INITDIALOG             = 0x0110,
+		WM_COMMAND                = 0x0111,
+		WM_SYSCOMMAND             = 0x0112,
+		WM_TIMER                  = 0x0113,
+		WM_HSCROLL                = 0x0114,
+		WM_VSCROLL                = 0x0115,
+		WM_INITMENU               = 0x0116,
+		WM_INITMENUPOPUP          = 0x0117,
+		WM_MENUSELECT             = 0x011F,
+		WM_MENUCHAR               = 0x0120,
+		WM_ENTERIDLE              = 0x0121,
+		WM_MENURBUTTONUP          = 0x0122,
+		WM_MENUDRAG               = 0x0123,
+		WM_MENUGETOBJECT          = 0x0124,
+		WM_UNINITMENUPOPUP        = 0x0125,
+		WM_MENUCOMMAND            = 0x0126,
+		WM_CTLCOLORMSGBOX         = 0x0132,
+		WM_CTLCOLOREDIT           = 0x0133,
+		WM_CTLCOLORLISTBOX        = 0x0134,
+		WM_CTLCOLORBTN            = 0x0135,
+		WM_CTLCOLORDLG            = 0x0136,
+		WM_CTLCOLORSCROLLBAR      = 0x0137,
+		WM_CTLCOLORSTATIC         = 0x0138,
+		WM_MOUSEMOVE              = 0x0200,
+		WM_LBUTTONDOWN            = 0x0201,
+		WM_LBUTTONUP              = 0x0202,
+		WM_LBUTTONDBLCLK          = 0x0203,
+		WM_RBUTTONDOWN            = 0x0204,
+		WM_RBUTTONUP              = 0x0205,
+		WM_RBUTTONDBLCLK          = 0x0206,
+		WM_MBUTTONDOWN            = 0x0207,
+		WM_MBUTTONUP              = 0x0208,
+		WM_MBUTTONDBLCLK          = 0x0209,
+		WM_MOUSEWHEEL             = 0x020A,
+		WM_PARENTNOTIFY           = 0x0210,
+		WM_ENTERMENULOOP          = 0x0211,
+		WM_EXITMENULOOP           = 0x0212,
+		WM_NEXTMENU               = 0x0213,
+		WM_SIZING                 = 0x0214,
+		WM_CAPTURECHANGED         = 0x0215,
+		WM_MOVING                 = 0x0216,
+		WM_DEVICECHANGE           = 0x0219,
+		WM_MDICREATE              = 0x0220,
+		WM_MDIDESTROY             = 0x0221,
+		WM_MDIACTIVATE            = 0x0222,
+		WM_MDIRESTORE             = 0x0223,
+		WM_MDINEXT                = 0x0224,
+		WM_MDIMAXIMIZE            = 0x0225,
+		WM_MDITILE                = 0x0226,
+		WM_MDICASCADE             = 0x0227,
+		WM_MDIICONARRANGE         = 0x0228,
+		WM_MDIGETACTIVE           = 0x0229,
+		WM_MDISETMENU             = 0x0230,
+		WM_ENTERSIZEMOVE          = 0x0231,
+		WM_EXITSIZEMOVE           = 0x0232,
+		WM_DROPFILES              = 0x0233,
+		WM_MDIREFRESHMENU         = 0x0234,
+		WM_IME_SETCONTEXT         = 0x0281,
+		WM_IME_NOTIFY             = 0x0282,
+		WM_IME_CONTROL            = 0x0283,
+		WM_IME_COMPOSITIONFULL    = 0x0284,
+		WM_IME_SELECT             = 0x0285,
+		WM_IME_CHAR               = 0x0286,
+		WM_IME_REQUEST            = 0x0288,
+		WM_IME_KEYDOWN            = 0x0290,
+		WM_IME_KEYUP              = 0x0291,
+		WM_MOUSEHOVER             = 0x02A1,
+		WM_MOUSELEAVE             = 0x02A3,
+		WM_CUT                    = 0x0300,
+		WM_COPY                   = 0x0301,
+		WM_PASTE                  = 0x0302,
+		WM_CLEAR                  = 0x0303,
+		WM_UNDO                   = 0x0304,
+		WM_RENDERFORMAT           = 0x0305,
+		WM_RENDERALLFORMATS       = 0x0306,
+		WM_DESTROYCLIPBOARD       = 0x0307,
+		WM_DRAWCLIPBOARD          = 0x0308,
+		WM_PAINTCLIPBOARD         = 0x0309,
+		WM_VSCROLLCLIPBOARD       = 0x030A,
+		WM_SIZECLIPBOARD          = 0x030B,
+		WM_ASKCBFORMATNAME        = 0x030C,
+		WM_CHANGECBCHAIN          = 0x030D,
+		WM_HSCROLLCLIPBOARD       = 0x030E,
+		WM_QUERYNEWPALETTE        = 0x030F,
+		WM_PALETTEISCHANGING      = 0x0310,
+		WM_PALETTECHANGED         = 0x0311,
+		WM_HOTKEY                 = 0x0312,
+		WM_PRINT                  = 0x0317,
+		WM_PRINTCLIENT            = 0x0318,
+		WM_HANDHELDFIRST          = 0x0358,
+		WM_HANDHELDLAST           = 0x035F,
+		WM_AFXFIRST               = 0x0360,
+		WM_AFXLAST                = 0x037F,
+		WM_PENWINFIRST            = 0x0380,
+		WM_PENWINLAST             = 0x038F,
+		WM_APP                    = 0x8000,
+		WM_USER                   = 0x0400
+	}
+
+	internal enum HitTest
+	{
+		HTERROR			= -2,
+		HTTRANSPARENT   = -1,
+		HTNOWHERE		= 0,
+		HTCLIENT		= 1,
+		HTCAPTION		= 2,
+		HTSYSMENU		= 3,
+		HTGROWBOX		= 4,
+		HTSIZE			= 4,
+		HTMENU			= 5,
+		HTHSCROLL		= 6,
+		HTVSCROLL		= 7,
+		HTMINBUTTON		= 8,
+		HTMAXBUTTON		= 9,
+		HTLEFT			= 10,
+		HTRIGHT			= 11,
+		HTTOP			= 12,
+		HTTOPLEFT		= 13,
+		HTTOPRIGHT		= 14,
+		HTBOTTOM		= 15,
+		HTBOTTOMLEFT	= 16,
+		HTBOTTOMRIGHT	= 17,
+		HTBORDER		= 18,
+		HTREDUCE		= 8,
+		HTZOOM			= 9 ,
+		HTSIZEFIRST		= 10,
+		HTSIZELAST		= 17,
+		HTOBJECT		= 19,
+		HTCLOSE			= 20,
+		HTHELP			= 21
+	}
+
+	internal enum ScrollBars : uint
+	{
+		SB_HORZ = 0,
+		SB_VERT = 1,
+		SB_CTL = 2,
+		SB_BOTH = 3
+	}
+
+	internal enum GetWindowLongIndex : int
+	{
+		GWL_STYLE = -16,
+		GWL_EXSTYLE = -20
+	}
+
+    // Hook Types  
+    internal enum HookType : int
+    {
+        WH_JOURNALRECORD = 0,
+        WH_JOURNALPLAYBACK = 1,
+        WH_KEYBOARD = 2,
+        WH_GETMESSAGE = 3,
+        WH_CALLWNDPROC = 4,
+        WH_CBT = 5,
+        WH_SYSMSGFILTER = 6,
+        WH_MOUSE = 7,
+        WH_HARDWARE = 8,
+        WH_DEBUG = 9,
+        WH_SHELL = 10,
+        WH_FOREGROUNDIDLE = 11,
+        WH_CALLWNDPROCRET = 12,
+        WH_KEYBOARD_LL = 13,
+        WH_MOUSE_LL = 14
+    }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Win32/NativeMethods.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Win32/NativeMethods.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Docking/Win32/NativeMethods.cs	(revision 2645)
@@ -0,0 +1,64 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Diagnostics.CodeAnalysis;
+using WeifenLuo.WinFormsUI.Docking.Win32;
+
+namespace WeifenLuo.WinFormsUI.Docking
+{
+    internal static class NativeMethods
+    {
+		[DllImport("User32.dll", CharSet=CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+		public static extern bool DragDetect(IntPtr hWnd, Point pt);
+
+        [DllImport("User32.dll", CharSet=CharSet.Auto)]
+        public static extern IntPtr GetFocus();
+
+        [DllImport("User32.dll", CharSet=CharSet.Auto)]
+        public static extern IntPtr SetFocus(IntPtr hWnd);
+
+        [DllImport("User32.dll", CharSet=CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
+
+        [DllImport("User32.dll", CharSet=CharSet.Auto)]
+        public static extern uint SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
+
+        [DllImport("User32.dll", CharSet=CharSet.Auto)]
+        public static extern int ShowWindow(IntPtr hWnd, short cmdShow);
+
+        [DllImport("User32.dll", CharSet=CharSet.Auto)]
+        public static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndAfter, int X, int Y, int Width, int Height, FlagsSetWindowPos flags);
+
+		[DllImport("user32.dll", CharSet = CharSet.Auto)]
+		public static extern int GetWindowLong(IntPtr hWnd, int Index);
+
+		[DllImport("user32.dll", CharSet = CharSet.Auto)]
+		public static extern int SetWindowLong(IntPtr hWnd, int Index, int Value);
+
+		[DllImport("user32.dll", CharSet=CharSet.Auto)]
+		public static extern int ShowScrollBar(IntPtr hWnd, int wBar, int bShow);
+
+		[DllImport("user32.dll", CharSet=CharSet.Auto)]
+        //*********************************
+        // FxCop bug, suppress the message
+        //*********************************
+        [SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", MessageId = "0")]
+		public static extern IntPtr WindowFromPoint(Point point);
+
+        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
+        public static extern int GetCurrentThreadId();
+
+        public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr SetWindowsHookEx(Win32.HookType code, HookProc func, IntPtr hInstance, int threadID);
+
+        [DllImport("user32.dll")]
+        public static extern int UnhookWindowsHookEx(IntPtr hhook);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wParam, IntPtr lParam);
+	}
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Properties/AssemblyInfo.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Properties/AssemblyInfo.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/Properties/AssemblyInfo.cs	(revision 2645)
@@ -0,0 +1,28 @@
+﻿using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: AssemblyTitle("DockPanel Suite for .Net 2.0")]
+[assembly: AssemblyDescription(".Net Docking Library for Windows Forms")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Weifen Luo")]
+[assembly: AssemblyProduct("DockPanel Suite")]
+[assembly: AssemblyCopyright("Copyright © Weifen Luo 2007")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: CLSCompliant(true)]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("9d690ef9-ce19-4c69-874c-e24d8eb36aff")]
+
+[assembly: AssemblyVersion("2.3.1.*")]
+[assembly: AssemblyFileVersion("2.3.1.0")]
+
+[module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope = "namespace", Target = "WeifenLuo.WinFormsUI.Docking", MessageId = "Weifen")]
+[module: SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", Scope = "namespace", Target = "WeifenLuo.WinFormsUI.Docking", MessageId = "Luo")]
+[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "WeifenLuo.WinFormsUI.Docking.Strings.resources", MessageId = "Weifen")]
+[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "WeifenLuo.WinFormsUI.Docking.Strings.resources", MessageId = "Luo")]
+[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope = "resource", Target = "WeifenLuo.WinFormsUI.Docking.Strings.resources", MessageId = "Dockable")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/WinFormsUI-2.3.1.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/WinFormsUI-2.3.1.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.3.1/WinFormsUI-2.3.1/WinFormsUI-2.3.1.csproj	(revision 2645)
@@ -0,0 +1,237 @@
+﻿<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{C75532C4-765B-418E-B09B-46D36B2ABDB1}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>WeifenLuo.WinFormsUI</RootNamespace>
+    <AssemblyName>WeifenLuo.WinFormsUI.Docking-2.3.1</AssemblyName>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+    <OldToolsVersion>2.0</OldToolsVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Design" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Docking\DockPanel.SplitterDragHandler.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPanel.DragHandler.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DragForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPanel.MdiClientController.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\AutoHideStripBase.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\InertButtonBase.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPanelSkin.cs">
+    </Compile>
+    <Compile Include="Docking\VS2005AutoHideStrip.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPanel.AutoHideWindow.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\VisibleNestedPaneCollection.cs" />
+    <Compile Include="Docking\DockAreasEditor.cs" />
+    <Compile Include="Docking\DockContent.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Docking\DockContentCollection.cs" />
+    <Compile Include="Docking\DockContentHandler.cs" />
+    <Compile Include="Docking\DockPanel.DockDragHandler.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\Helpers\DockHelper.cs" />
+    <Compile Include="Docking\NestedPaneCollection.cs" />
+    <Compile Include="Docking\DockOutlineBase.cs" />
+    <Compile Include="Docking\DockPane.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPaneCaptionBase.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\VS2005DockPaneCaption.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPaneCollection.cs" />
+    <Compile Include="Docking\DockPanel.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPanelExtender.cs" />
+    <Compile Include="Docking\DockPanel.Persistor.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPane.SplitterControl.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Docking\DockPaneStripBase.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\VS2005DockPaneStrip.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockWindow.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DockWindowCollection.cs" />
+    <Compile Include="Docking\DockWindow.SplitterControl.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\DummyControl.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\Enums.cs" />
+    <Compile Include="Docking\DockContentEventArgs.cs" />
+    <Compile Include="Docking\FloatWindow.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Docking\FloatWindowCollection.cs" />
+    <Compile Include="Docking\DockPanel.FocusManager.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\Interfaces.cs" />
+    <Compile Include="Docking\Measures.cs" />
+    <Compile Include="Docking\NestedDockingStatus.cs" />
+    <Compile Include="Docking\SplitterBase.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Docking\Helpers\DrawHelper.cs" />
+    <Compile Include="Docking\Localization.cs" />
+    <Compile Include="Docking\Helpers\ResourceHelper.cs" />
+    <Compile Include="Docking\Helpers\Win32Helper.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Docking\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Docking\Strings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Strings.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Docking\Win32\Enums.cs" />
+    <Compile Include="Docking\Win32\NativeMethods.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Docking\Resources.resx">
+      <SubType>Designer</SubType>
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Docking\Strings.resx">
+      <SubType>Designer</SubType>
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond_Bottom.bmp" />
+    <None Include="Docking\Resources\Dockindicator_PaneDiamond_Fill.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond_Hotspot.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond_HotspotIndex.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond_Left.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond_Right.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PaneDiamond_Top.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelBottom.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelBottom_Active.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelFill.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelFill_Active.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelLeft.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelLeft_Active.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelRight.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelRight_Active.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelTop.bmp" />
+    <None Include="Docking\Resources\DockIndicator_PanelTop_Active.bmp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Docking\Resources\DockPane_AutoHide.bmp" />
+    <None Include="Docking\Resources\DockPane_Close.bmp" />
+    <None Include="Docking\Resources\DockPane_Dock.bmp" />
+    <None Include="Docking\Resources\DockPane_Option.bmp" />
+    <None Include="Docking\Resources\DockPane_OptionOverflow.bmp" />
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Docking\DockPanel.bmp" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLab.log4net-1.2.10.0.csproj
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLab.log4net-1.2.10.0.csproj	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLab.log4net-1.2.10.0.csproj	(revision 2645)
@@ -0,0 +1,122 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{1B3063DB-D71C-4A6A-A359-883E8F53A140}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.log4net</RootNamespace>
+    <AssemblyName>HeuristicLab.log4net-1.2.10.0</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\HeuristicLab.log4net-1.2.10.0.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.log4net-1.2.10.0.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.log4net-1.2.10.0.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HeuristicLablog4netPlugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="log4net License.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="log4net.dll">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLab.log4net-1.2.10.0.csproj.user
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLab.log4net-1.2.10.0.csproj.user	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLab.log4net-1.2.10.0.csproj.user	(revision 2645)
@@ -0,0 +1,5 @@
+﻿<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <ProjectView>ProjectFiles</ProjectView>
+  </PropertyGroup>
+</Project>
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLablog4netPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLablog4netPlugin.cs	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/HeuristicLablog4netPlugin.cs	(revision 2645)
@@ -0,0 +1,34 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.SQLite {
+  [Plugin("HeuristicLab.log4net-1.2.10.0")]
+  [PluginFile("HeuristicLab.log4net-1.2.10.0.dll", PluginFileType.Assembly)]
+  [PluginFile("log4net.dll", PluginFileType.Assembly)]
+  [PluginFile("log4net License.txt", PluginFileType.License)]
+  public class HeuristicLabSQLitePlugin : PluginBase {
+  }
+}
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/Properties/AssemblyInfo.frame
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/Properties/AssemblyInfo.frame	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/Properties/AssemblyInfo.frame	(revision 2645)
@@ -0,0 +1,38 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.log4net")]
+[assembly: AssemblyDescription("Transport plugin for log4net")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3f5083f8-2738-4573-b230-e9928ef61e6b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.2.10.0")]
+[assembly: AssemblyFileVersion("1.2.10.0")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/log4net License.txt
===================================================================
--- /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/log4net License.txt	(revision 2645)
+++ /trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.log4net/1.2.10.0/log4net License.txt	(revision 2645)
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
Index: /trunk/sources/HeuristicLab.Grid/3.2/HeuristicLabGridPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.Grid/3.2/HeuristicLabGridPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.Grid/3.2/HeuristicLabGridPlugin.cs	(revision 2645)
@@ -31,4 +31,5 @@
   [PluginDependency("HeuristicLab.Core-3.2")]
   [PluginDependency("HeuristicLab.Tracing-3.2")]
+  [PluginDependency("HeuristicLab.SQLite-1.0.65.0")]
   public class HeuristicLabGridPlugin : PluginBase {
   }
Index: /trunk/sources/HeuristicLab.LinearRegression/3.2/HeuristicLab.LinearRegression-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.LinearRegression/3.2/HeuristicLab.LinearRegression-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.LinearRegression/3.2/HeuristicLab.LinearRegression-3.2.csproj	(revision 2645)
@@ -92,8 +92,4 @@
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\ALGLIB\ALGLIB.csproj">
-      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
-      <Name>ALGLIB</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Common\3.2\HeuristicLab.Common-3.2.csproj">
       <Project>{1FC004FC-59AF-4249-B1B6-FF25873A20E4}</Project>
@@ -111,4 +107,8 @@
       <Project>{F473D9AF-3F09-4296-9F28-3C65118DAFFA}</Project>
       <Name>HeuristicLab.Data-3.2</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\ALGLIB-2.1.2.2591\ALGLIB-2.1.2.2591.csproj">
+      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
+      <Name>ALGLIB-2.1.2.2591</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.GP.Interfaces\3.3\HeuristicLab.GP.Interfaces-3.3.csproj">
Index: /trunk/sources/HeuristicLab.LinearRegression/3.2/HeuristicLabLinearRegressionPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.LinearRegression/3.2/HeuristicLabLinearRegressionPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.LinearRegression/3.2/HeuristicLabLinearRegressionPlugin.cs	(revision 2645)
@@ -27,5 +27,5 @@
   [Plugin("HeuristicLab.LinearRegression-3.2")]
   [PluginFile("HeuristicLab.LinearRegression-3.2.dll", PluginFileType.Assembly)]
-  [PluginDependency("ALGLIB")]
+  [PluginDependency("HeuristicLab.ALGLIB-2.1.2.2591")]
   [PluginDependency("HeuristicLab.Common-3.2")]
   [PluginDependency("HeuristicLab.Core-3.2")]
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.2/HeuristicLab.MainForm.WindowsForms-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.2/HeuristicLab.MainForm.WindowsForms-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.2/HeuristicLab.MainForm.WindowsForms-3.2.csproj	(revision 2645)
@@ -140,4 +140,8 @@
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\WinFormsUI-2.3.1\WinFormsUI-2.3.1.csproj">
+      <Project>{C75532C4-765B-418E-B09B-46D36B2ABDB1}</Project>
+      <Name>WinFormsUI-2.3.1</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.MainForm\3.2\HeuristicLab.MainForm-3.2.csproj">
       <Project>{3BD61258-31DA-4B09-89C0-4F71FEF5F05A}</Project>
@@ -147,8 +151,4 @@
       <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
       <Name>HeuristicLab.PluginInfrastructure</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\WinFormsUI\WinFormsUI.csproj">
-      <Project>{C75532C4-765B-418E-B09B-46D36B2ABDB1}</Project>
-      <Name>WinFormsUI</Name>
     </ProjectReference>
   </ItemGroup>
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.2/HeuristicLabMainFormWindowsFormsPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.2/HeuristicLabMainFormWindowsFormsPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.2/HeuristicLabMainFormWindowsFormsPlugin.cs	(revision 2645)
@@ -27,7 +27,7 @@
 namespace HeuristicLab.MainForm.WindowsForms {
   [Plugin("HeuristicLab.MainForm.WindowsForms-3.2")]
-  [PluginFile("HeuristicLab.MainForm.WindowsForms-3.2.dll", PluginFileType.Assembly)]
-  [PluginFile("WeifenLuo.WinFormsUI.Docking.dll", PluginFileType.Assembly)]
+  [PluginFile("HeuristicLab.MainForm.WindowsForms-3.2.dll", PluginFileType.Assembly)]  
   [PluginDependency("HeuristicLab.MainForm-3.2")]
+  [PluginDependency("HeuristicLab.WinFormsUI-2.3.1")]
   public class HeuristicLabMainFormTestPlugin : PluginBase {
   }
Index: /trunk/sources/HeuristicLab.Modeling.Database.SQLServerCompact/3.2/HeuristicLab.Modeling.Database.SQLServerCompact-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Modeling.Database.SQLServerCompact/3.2/HeuristicLab.Modeling.Database.SQLServerCompact-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.Modeling.Database.SQLServerCompact/3.2/HeuristicLab.Modeling.Database.SQLServerCompact-3.2.csproj	(revision 2645)
@@ -111,8 +111,4 @@
       <Name>HeuristicLab.PluginInfrastructure</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\HeuristicLab.SQLServerCompact\3.2\HeuristicLab.SQLServerCompact-3.2.csproj">
-      <Project>{31DD6385-7276-49ED-9533-823D4CDF3D2A}</Project>
-      <Name>HeuristicLab.SQLServerCompact-3.2</Name>
-    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
Index: /trunk/sources/HeuristicLab.Modeling.Database.SQLServerCompact/3.2/HeuristicLabModelingDatabaseSQLServerCompactPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.Modeling.Database.SQLServerCompact/3.2/HeuristicLabModelingDatabaseSQLServerCompactPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.Modeling.Database.SQLServerCompact/3.2/HeuristicLabModelingDatabaseSQLServerCompactPlugin.cs	(revision 2645)
@@ -33,5 +33,5 @@
   [PluginDependency("HeuristicLab.Modeling-3.2")]
   [PluginDependency("HeuristicLab.Modeling.Database-3.2")]
-  [PluginDependency("HeuristicLab.SQLServerCompact-3.2")]  
+  [PluginDependency("HeuristicLab.SQLServerCompact-3.5")]  
   public class HeuristicLabModelingDatabaseSQLServerCompactPlugin : PluginBase {
   }
Index: /trunk/sources/HeuristicLab.Modeling/3.2/HeuristicLab.Modeling-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Modeling/3.2/HeuristicLab.Modeling-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.Modeling/3.2/HeuristicLab.Modeling-3.2.csproj	(revision 2645)
@@ -130,8 +130,4 @@
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\ALGLIB\ALGLIB.csproj">
-      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
-      <Name>ALGLIB</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Common\3.2\HeuristicLab.Common-3.2.csproj">
       <Project>{1FC004FC-59AF-4249-B1B6-FF25873A20E4}</Project>
@@ -149,4 +145,8 @@
       <Project>{F473D9AF-3F09-4296-9F28-3C65118DAFFA}</Project>
       <Name>HeuristicLab.Data-3.2</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\ALGLIB-2.1.2.2591\ALGLIB-2.1.2.2591.csproj">
+      <Project>{44456535-5DB5-454A-BE2B-7426DA6700B6}</Project>
+      <Name>ALGLIB-2.1.2.2591</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Operators\3.2\HeuristicLab.Operators-3.2.csproj">
Index: /trunk/sources/HeuristicLab.Modeling/3.2/HeuristicLabModelingPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.Modeling/3.2/HeuristicLabModelingPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.Modeling/3.2/HeuristicLabModelingPlugin.cs	(revision 2645)
@@ -28,5 +28,5 @@
   [Plugin("HeuristicLab.Modeling-3.2")]
   [PluginFile("HeuristicLab.Modeling-3.2.dll", PluginFileType.Assembly)]
-  [PluginDependency("ALGLIB")]
+  [PluginDependency("HeuristicLab.ALGLIB-2.1.2.2591")]
   [PluginDependency("HeuristicLab.Common-3.2")]
   [PluginDependency("HeuristicLab.Core-3.2")]
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/HeuristicLab.SupportVectorMachines-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/HeuristicLab.SupportVectorMachines-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/HeuristicLab.SupportVectorMachines-3.2.csproj	(revision 2645)
@@ -128,4 +128,8 @@
       <Name>HeuristicLab.Data-3.2</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.ExtLibs\HeuristicLab.LibSVM\1.6.3\LibSVM-1.6.3\LibSVM-1.6.3.csproj">
+      <Project>{A16F23B5-FB62-499E-A831-26953AA56FE2}</Project>
+      <Name>LibSVM-1.6.3</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Logging\3.2\HeuristicLab.Logging-3.2.csproj">
       <Project>{4095C92C-5A4C-44BC-9963-5F384CF5CC3F}</Project>
@@ -160,8 +164,4 @@
       <Name>HeuristicLab.SequentialEngine-3.2</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\LibSVM\LibSVM.csproj">
-      <Project>{A16F23B5-FB62-499E-A831-26953AA56FE2}</Project>
-      <Name>LibSVM</Name>
-    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/HeuristicLabSupportVectorMachinesPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/HeuristicLabSupportVectorMachinesPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/HeuristicLabSupportVectorMachinesPlugin.cs	(revision 2645)
@@ -29,8 +29,8 @@
   [Plugin("HeuristicLab.SupportVectorMachines-3.2")]
   [PluginFile("HeuristicLab.SupportVectorMachines-3.2.dll", PluginFileType.Assembly)]
-  [PluginFile("LibSVM.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Core-3.2")]
   [PluginDependency("HeuristicLab.Data-3.2")]
   [PluginDependency("HeuristicLab.DataAnalysis-3.2")]
+  [PluginDependency("HeuristicLab.LibSVM-1.6.3")]
   [PluginDependency("HeuristicLab.Modeling-3.2")]
   [PluginDependency("HeuristicLab.SequentialEngine-3.2")]
Index: /trunk/sources/HeuristicLab.Tracing/3.2/HeuristicLab.Tracing-3.2.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Tracing/3.2/HeuristicLab.Tracing-3.2.csproj	(revision 2644)
+++ /trunk/sources/HeuristicLab.Tracing/3.2/HeuristicLab.Tracing-3.2.csproj	(revision 2645)
@@ -68,5 +68,5 @@
     <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>libs\release\log4net.dll</HintPath>
+      <HintPath>..\..\HeuristicLab.ExtLibs\HeuristicLab.log4net\1.2.10.0\log4net.dll</HintPath>
     </Reference>
     <Reference Include="System" />
@@ -116,7 +116,4 @@
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="log4net licence.txt">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Index: /trunk/sources/HeuristicLab.Tracing/3.2/HeuristicLabTracingPlugin.cs
===================================================================
--- /trunk/sources/HeuristicLab.Tracing/3.2/HeuristicLabTracingPlugin.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.Tracing/3.2/HeuristicLabTracingPlugin.cs	(revision 2645)
@@ -1,3 +1,24 @@
-﻿using HeuristicLab.PluginInfrastructure;
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.PluginInfrastructure;
 
 namespace HeuristicLab.Tracing {
@@ -5,7 +26,6 @@
   [Plugin("HeuristicLab.Tracing-3.2")]
   [PluginFile("HeuristicLab.Tracing-3.2.dll", PluginFileType.Assembly)]
-  [PluginFile("log4net.dll", PluginFileType.Assembly)]
-  [PluginFile("log4net licence.txt", PluginFileType.License)]
   [PluginFile("HeuristicLab.log4net.xml", PluginFileType.Data)]
+  [PluginDependency("HeuristicLab.log4net-1.2.10.0")]
   public class HeuristicLabPersistencePlugin : PluginBase {}
 
Index: /trunk/sources/HeuristicLab.Tracing/3.2/HiveLogger.cs
===================================================================
--- /trunk/sources/HeuristicLab.Tracing/3.2/HiveLogger.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.Tracing/3.2/HiveLogger.cs	(revision 2645)
@@ -1,3 +1,24 @@
-﻿using System;
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
 using HeuristicLab.Tracing.Properties;
 using log4net;
Index: /trunk/sources/HeuristicLab.Tracing/3.2/Logger.cs
===================================================================
--- /trunk/sources/HeuristicLab.Tracing/3.2/Logger.cs	(revision 2644)
+++ /trunk/sources/HeuristicLab.Tracing/3.2/Logger.cs	(revision 2645)
@@ -1,3 +1,24 @@
-﻿using System;
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
 using HeuristicLab.Tracing.Properties;
 using log4net;
Index: unk/sources/HeuristicLab.Tracing/3.2/log4net licence.txt
===================================================================
--- /trunk/sources/HeuristicLab.Tracing/3.2/log4net licence.txt	(revision 2644)
+++ 	(revision )
@@ -1,201 +1,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
Index: /trunk/sources/HeuristicLab/Files.txt
===================================================================
--- /trunk/sources/HeuristicLab/Files.txt	(revision 2644)
+++ /trunk/sources/HeuristicLab/Files.txt	(revision 2645)
@@ -4,7 +4,4 @@
 HeuristicLab.PluginInfrastructure:ICSharpCode.SharpZipLib License.txt
 HeuristicLab.PluginInfrastructure:ICSharpCode.SharpZipLib.dll
-
-ALGLIB:ALGLIB.dll
-ALGLIB:ALGLIB License.txt
 
 HeuristicLab.AdvancedOptimizationFrontend\3.2:HeuristicLab.AdvancedOptimizationFrontend-3.2.dll 
@@ -74,5 +71,4 @@
 
 HeuristicLab.LinearRegression\3.2:HeuristicLab.LinearRegression-3.2.dll 
-HeuristicLab.LinearRegression\3.2:ALGLIB License.txt 
 
 HeuristicLab.Logging\3.2:HeuristicLab.Logging-3.2.dll 
@@ -81,7 +77,4 @@
 HeuristicLab.MainForm.Test\3.2:HeuristicLab.MainForm.Test-3.2.dll 
 HeuristicLab.MainForm.WindowsForms\3.2:HeuristicLab.MainForm.WindowsForms-3.2.dll 
-
-WinFormsUI:WeifenLuo.WinFormsUI.Docking.dll 
-WinFormsUI:WeifenLuo.WinFormsUI.Docking License.txt 
 
 HeuristicLab.Modeling\3.2:HeuristicLab.Modeling-3.2.dll 
@@ -111,15 +104,7 @@
 HeuristicLab.SimOpt\3.2:HeuristicLab.SimOpt-3.2.dll 
 
-HeuristicLab.SQLite\3.2:HeuristicLab.SQLite-3.2.dll 
-HeuristicLab.SQLite\3.2:SQLite License.txt 
-HeuristicLab.SQLite\3.2:SQLite.NET.chm 
-
-HeuristicLab.SQLServerCompact\3.2:HeuristicLab.SQLServerCompact-3.2.dll 
-HeuristicLab.SQLServerCompact\3.2:System.Data.SqlServerCe.dll 
-
 HeuristicLab.StatisticalAnalysis\3.2:HeuristicLab.StatisticalAnalysis-3.2.dll 
 
 HeuristicLab.SupportVectorMachines\3.2:HeuristicLab.SupportVectorMachines-3.2.dll 
-LibSVM:LibSVM.dll 
 
 HeuristicLab.TestFunctions\3.2:HeuristicLab.TestFunctions-3.2.dll 
@@ -127,6 +112,4 @@
 
 HeuristicLab.Tracing\3.2:HeuristicLab.Tracing-3.2.dll 
-HeuristicLab.Tracing\3.2:log4net.dll 
-HeuristicLab.Tracing\3.2:log4net licence.txt 
 HeuristicLab.Tracing\3.2:HeuristicLab.log4net.xml 
 HeuristicLab.Tracing\3.2:HeuristicLab.Hive.log4net.xml 
@@ -140,2 +123,27 @@
 HeuristicLab.Security.ADODataAccess\3.2:HeuristicLab.Security.ADODataAccess-3.2.dll 
 HeuristicLab.Security.Server\3.2:HeuristicLab.Security.Server-3.2.dll 
+
+;External Libraries
+HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\ALGLIB-2.1.2.2591:ALGLIB-2.1.2.2591.dll
+HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\HeuristicLab.ALGLIB-2.1.2.2591:ALGLIB License.txt
+HeuristicLab.ExtLibs\HeuristicLab.ALGLIB\2.1.2.2591\HeuristicLab.ALGLIB-2.1.2.2591:HeuristicLab.ALGLIB-2.1.2.2591.dll
+
+HeuristicLab.ExtLibs\HeuristicLab.LibSVM\1.6.3\LibSVM-1.6.3:LibSVM-1.6.3.dll 
+HeuristicLab.ExtLibs\HeuristicLab.LibSVM\1.6.3\HeuristicLab.LibSVM-1.6.3:HeuristicLab.LibSVM-1.6.3.dll
+HeuristicLab.ExtLibs\HeuristicLab.LibSVM\1.6.3\HeuristicLab.LibSVM-1.6.3:LibSVM License.txt
+
+HeuristicLab.ExtLibs\HeuristicLab.log4net\1.2.10.0:HeuristicLab.log4net-1.2.10.0.dll
+HeuristicLab.ExtLibs\HeuristicLab.log4net\1.2.10.0:log4net.dll 
+HeuristicLab.ExtLibs\HeuristicLab.log4net\1.2.10.0:log4net License.txt 
+
+HeuristicLab.ExtLibs\HeuristicLab.SQLite\1.0.65.0:HeuristicLab.SQLite-1.0.65.0.dll 
+HeuristicLab.ExtLibs\HeuristicLab.SQLite\1.0.65.0:SQLite License.txt 
+HeuristicLab.ExtLibs\HeuristicLab.SQLite\1.0.65.0:SQLite.NET.chm 
+
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5:HeuristicLab.SQLServerCompact-3.5.dll 
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5:System.Data.SqlServerCe-3.5.dll 
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5:SQLServer Compact license.txt
+
+HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\HeuristicLab.WinFormsUI-2.3.1:HeuristicLab.WinFormsUI-2.3.1.dll
+HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\WinFormsUI-2.3.1:WeifenLuo.WinFormsUI.Docking-2.3.1.dll 
+HeuristicLab.ExtLibs\HeuristicLab.WinFormsUI\2.3.1\WinFormsUI-2.3.1::WeifenLuo.WinFormsUI.Docking License.txt 
Index: /trunk/sources/HeuristicLab/Files.x64.txt
===================================================================
--- /trunk/sources/HeuristicLab/Files.x64.txt	(revision 2644)
+++ /trunk/sources/HeuristicLab/Files.x64.txt	(revision 2645)
@@ -2,11 +2,11 @@
 ; This file contains a list of all x64 specific files
 
-HeuristicLab.SQLServerCompact\3.2\x64\sqlceca35.dll
-HeuristicLab.SQLServerCompact\3.2\x64\sqlcecompact35.dll
-HeuristicLab.SQLServerCompact\3.2\x64\sqlceer35EN.dll
-HeuristicLab.SQLServerCompact\3.2\x64\sqlceme35.dll
-HeuristicLab.SQLServerCompact\3.2\x64\sqlceoledb35.dll
-HeuristicLab.SQLServerCompact\3.2\x64\sqlceqp35.dll
-HeuristicLab.SQLServerCompact\3.2\x64\sqlcese35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlceca35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlcecompact35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlceer35EN.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlceme35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlceoledb35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlceqp35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x64\sqlcese35.dll
 
-HeuristicLab.SQLite\3.2\x64\System.Data.SQLite.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLite\1.0.65.0\x64\System.Data.SQLite.dll
Index: /trunk/sources/HeuristicLab/Files.x86.txt
===================================================================
--- /trunk/sources/HeuristicLab/Files.x86.txt	(revision 2644)
+++ /trunk/sources/HeuristicLab/Files.x86.txt	(revision 2645)
@@ -2,11 +2,11 @@
 ; This file contains a list of all x86 specific files
 
-HeuristicLab.SQLServerCompact\3.2\x86\sqlceca35.dll
-HeuristicLab.SQLServerCompact\3.2\x86\sqlcecompact35.dll
-HeuristicLab.SQLServerCompact\3.2\x86\sqlceer35EN.dll
-HeuristicLab.SQLServerCompact\3.2\x86\sqlceme35.dll
-HeuristicLab.SQLServerCompact\3.2\x86\sqlceoledb35.dll
-HeuristicLab.SQLServerCompact\3.2\x86\sqlceqp35.dll
-HeuristicLab.SQLServerCompact\3.2\x86\sqlcese35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlceca35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlcecompact35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlceer35EN.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlceme35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlceoledb35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlceqp35.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLServerCompact\3.5\x86\sqlcese35.dll
 
-HeuristicLab.SQLite\3.2\x86\System.Data.SQLite.dll
+HeuristicLab.ExtLibs\HeuristicLab.SQLite\1.0.65.0\x86\System.Data.SQLite.dll
