Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.ALGLIB/3.17.0/ALGLIB-3.17.0/ap.cs

Last change on this file was 17931, checked in by gkronber, 3 years ago

#3117: update alglib to version 3.17

File size: 99.0 KB
Line 
1/**************************************************************************
2ALGLIB 3.17.0 (source code generated 2020-12-27)
3Copyright (c) Sergey Bochkanov (ALGLIB project).
4
5>>> SOURCE LICENSE >>>
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation (www.fsf.org); either version 2 of the
9License, or (at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16A copy of the GNU General Public License is available at
17http://www.fsf.org/licensing/licenses
18>>> END OF LICENSE >>>
19**************************************************************************/
20using System;
21public partial class alglib
22{
23    /********************************************************************
24    Callback definitions for optimizers/fitters/solvers.
25   
26    Callbacks for unparameterized (general) functions:
27    * ndimensional_func         calculates f(arg), stores result to func
28    * ndimensional_grad         calculates func = f(arg),
29                                grad[i] = df(arg)/d(arg[i])
30    * ndimensional_hess         calculates func = f(arg),
31                                grad[i] = df(arg)/d(arg[i]),
32                                hess[i,j] = d2f(arg)/(d(arg[i])*d(arg[j]))
33   
34    Callbacks for systems of functions:
35    * ndimensional_fvec         calculates vector function f(arg),
36                                stores result to fi
37    * ndimensional_jac          calculates f[i] = fi(arg)
38                                jac[i,j] = df[i](arg)/d(arg[j])
39                               
40    Callbacks for  parameterized  functions,  i.e.  for  functions  which
41    depend on two vectors: P and Q.  Gradient  and Hessian are calculated
42    with respect to P only.
43    * ndimensional_pfunc        calculates f(p,q),
44                                stores result to func
45    * ndimensional_pgrad        calculates func = f(p,q),
46                                grad[i] = df(p,q)/d(p[i])
47    * ndimensional_phess        calculates func = f(p,q),
48                                grad[i] = df(p,q)/d(p[i]),
49                                hess[i,j] = d2f(p,q)/(d(p[i])*d(p[j]))
50
51    Callbacks for progress reports:
52    * ndimensional_rep          reports current position of optimization algo   
53   
54    Callbacks for ODE solvers:
55    * ndimensional_ode_rp       calculates dy/dx for given y[] and x
56   
57    Callbacks for integrators:
58    * integrator1_func          calculates f(x) for given x
59                                (additional parameters xminusa and bminusx
60                                contain x-a and b-x)
61    ********************************************************************/
62    public delegate void ndimensional_func (double[] arg, ref double func, object obj);
63    public delegate void ndimensional_grad (double[] arg, ref double func, double[] grad, object obj);
64    public delegate void ndimensional_hess (double[] arg, ref double func, double[] grad, double[,] hess, object obj);
65   
66    public delegate void ndimensional_fvec (double[] arg, double[] fi, object obj);
67    public delegate void ndimensional_jac  (double[] arg, double[] fi, double[,] jac, object obj);
68   
69    public delegate void ndimensional_pfunc(double[] p, double[] q, ref double func, object obj);
70    public delegate void ndimensional_pgrad(double[] p, double[] q, ref double func, double[] grad, object obj);
71    public delegate void ndimensional_phess(double[] p, double[] q, ref double func, double[] grad, double[,] hess, object obj);
72   
73    public delegate void ndimensional_rep(double[] arg, double func, object obj);
74
75    public delegate void ndimensional_ode_rp (double[] y, double x, double[] dy, object obj);
76
77    public delegate void integrator1_func (double x, double xminusa, double bminusx, ref double f, object obj);
78
79    /********************************************************************
80    Class defining a complex number with double precision.
81    ********************************************************************/
82    public struct complex
83    {
84        public double x;
85        public double y;
86
87        public complex(double _x)
88        {
89            x = _x;
90            y = 0;
91        }
92        public complex(double _x, double _y)
93        {
94            x = _x;
95            y = _y;
96        }
97        public static implicit operator complex(double _x)
98        {
99            return new complex(_x);
100        }
101        public static bool operator==(complex lhs, complex rhs)
102        {
103            return ((double)lhs.x==(double)rhs.x) & ((double)lhs.y==(double)rhs.y);
104        }
105        public static bool operator!=(complex lhs, complex rhs)
106        {
107            return ((double)lhs.x!=(double)rhs.x) | ((double)lhs.y!=(double)rhs.y);
108        }
109        public static complex operator+(complex lhs)
110        {
111            return lhs;
112        }
113        public static complex operator-(complex lhs)
114        {
115            return new complex(-lhs.x,-lhs.y);
116        }
117        public static complex operator+(complex lhs, complex rhs)
118        {
119            return new complex(lhs.x+rhs.x,lhs.y+rhs.y);
120        }
121        public static complex operator-(complex lhs, complex rhs)
122        {
123            return new complex(lhs.x-rhs.x,lhs.y-rhs.y);
124        }
125        public static complex operator*(complex lhs, complex rhs)
126        {
127            return new complex(lhs.x*rhs.x-lhs.y*rhs.y, lhs.x*rhs.y+lhs.y*rhs.x);
128        }
129        public static complex operator/(complex lhs, complex rhs)
130        {
131            complex result;
132            double e;
133            double f;
134            if( System.Math.Abs(rhs.y)<System.Math.Abs(rhs.x) )
135            {
136                e = rhs.y/rhs.x;
137                f = rhs.x+rhs.y*e;
138                result.x = (lhs.x+lhs.y*e)/f;
139                result.y = (lhs.y-lhs.x*e)/f;
140            }
141            else
142            {
143                e = rhs.x/rhs.y;
144                f = rhs.y+rhs.x*e;
145                result.x = (lhs.y+lhs.x*e)/f;
146                result.y = (-lhs.x+lhs.y*e)/f;
147            }
148            return result;
149        }
150        public override int GetHashCode()
151        {
152            return x.GetHashCode() ^ y.GetHashCode();
153        }
154        public override bool Equals(object obj)
155        {
156            if( obj is byte)
157                return Equals(new complex((byte)obj));
158            if( obj is sbyte)
159                return Equals(new complex((sbyte)obj));
160            if( obj is short)
161                return Equals(new complex((short)obj));
162            if( obj is ushort)
163                return Equals(new complex((ushort)obj));
164            if( obj is int)
165                return Equals(new complex((int)obj));
166            if( obj is uint)
167                return Equals(new complex((uint)obj));
168            if( obj is long)
169                return Equals(new complex((long)obj));
170            if( obj is ulong)
171                return Equals(new complex((ulong)obj));
172            if( obj is float)
173                return Equals(new complex((float)obj));
174            if( obj is double)
175                return Equals(new complex((double)obj));
176            if( obj is decimal)
177                return Equals(new complex((double)(decimal)obj));
178            return base.Equals(obj);
179        }   
180    }   
181   
182    /********************************************************************
183    Class defining an ALGLIB exception
184    ********************************************************************/
185    public class alglibexception : System.Exception
186    {
187        public string msg;
188        public alglibexception(string s)
189        {
190            msg = s;
191        }
192    }
193   
194    /********************************************************************
195    Critical failure, resilts in immediate termination of entire program.
196    ********************************************************************/
197    public static void AE_CRITICAL_ASSERT(bool x)
198    {
199        if( !x )
200            System.Environment.FailFast("ALGLIB: critical error");
201    }
202   
203    /********************************************************************
204    ALGLIB object, parent  class  for  all  internal  AlgoPascal  objects
205    managed by ALGLIB.
206   
207    Any internal AlgoPascal object inherits from this class.
208   
209    User-visible objects inherit from alglibobject (see below).
210    ********************************************************************/
211    public abstract class apobject
212    {
213        public abstract void init();
214        public abstract apobject make_copy();
215    }
216   
217    /********************************************************************
218    ALGLIB object, parent class for all user-visible objects  managed  by
219    ALGLIB.
220   
221    Methods:
222        _deallocate()       deallocation:
223                            * in managed ALGLIB it does nothing
224                            * in native ALGLIB it clears  dynamic  memory
225                              being  hold  by  object  and  sets internal
226                              reference to null.
227        make_copy()         creates deep copy of the object.
228                            Works in both managed and native versions  of
229                            ALGLIB.
230    ********************************************************************/
231    public abstract class alglibobject : IDisposable
232    {
233        public virtual void _deallocate() {}
234        public abstract alglibobject make_copy();
235        public void Dispose()
236        {
237            _deallocate();
238        }
239    }
240   
241    /********************************************************************
242    xparams object, used to pass additional parameters like multithreading
243    settings, and several predefined values
244    ********************************************************************/
245    public class xparams
246    {
247        public ulong flags;
248        public xparams(ulong v)
249        {
250            flags = v;
251        }
252    }
253    private static ulong FLG_THREADING_MASK          = 0x7;
254    private static   int FLG_THREADING_SHIFT         = 0;
255    private static ulong FLG_THREADING_USE_GLOBAL    = 0x0;
256    private static ulong FLG_THREADING_SERIAL        = 0x1;
257    private static ulong FLG_THREADING_PARALLEL      = 0x2;
258    public static xparams serial   = new xparams(FLG_THREADING_SERIAL);
259    public static xparams parallel = new xparams(FLG_THREADING_PARALLEL);
260
261    /********************************************************************
262    Global flags, split into several char-sized variables in order
263    to avoid problem with non-atomic reads/writes (single-byte ops
264    are atomic on all modern architectures);
265   
266    Following variables are included:
267    * threading-related settings
268    ********************************************************************/
269    public static byte global_threading_flags = (byte)(FLG_THREADING_SERIAL>>FLG_THREADING_SHIFT);
270   
271    public static void setglobalthreading(xparams p)
272    {
273        AE_CRITICAL_ASSERT(p!=null);
274        ae_set_global_threading(p.flags);
275    }
276   
277    public static void ae_set_global_threading(ulong flg_value)
278    {
279        flg_value = flg_value&FLG_THREADING_MASK;
280        AE_CRITICAL_ASSERT(flg_value==FLG_THREADING_SERIAL || flg_value==FLG_THREADING_PARALLEL);
281        global_threading_flags = (byte)(flg_value>>FLG_THREADING_SHIFT);
282    }
283   
284    public static ulong ae_get_global_threading()
285    {
286        return ((ulong)global_threading_flags)<<FLG_THREADING_SHIFT;
287    }
288   
289    static ulong ae_get_effective_threading(xparams p)
290    {
291        if( p==null || (p.flags&FLG_THREADING_MASK)==FLG_THREADING_USE_GLOBAL )
292            return ((ulong)global_threading_flags)<<FLG_THREADING_SHIFT;
293        return p.flags&FLG_THREADING_MASK;
294    }
295   
296    /********************************************************************
297    Deallocation of ALGLIB object:
298    * in managed ALGLIB this method just sets refence to null
299    * in native ALGLIB call of this method:
300      1) clears dynamic memory being hold by  object  and  sets  internal
301         reference to null.
302      2) sets to null variable being passed to this method
303   
304    IMPORTANT (1): in  native  edition  of  ALGLIB,  obj becomes unusable
305                   after this call!!!  It  is  possible  to  save  a copy
306                   of reference in another variable (original variable is
307                   set to null), but any attempt to work with this object
308                   will crash your program.
309   
310    IMPORTANT (2): memory owned by object will be recycled by GC  in  any
311                   case. This method just enforces IMMEDIATE deallocation.
312    ********************************************************************/
313    public static void deallocateimmediately<T>(ref T obj) where T : alglib.alglibobject
314    {
315        obj._deallocate();
316        obj = null;
317    }
318
319    /********************************************************************
320    Allocation counter:
321    * in managed ALGLIB it always returns 0 (dummy code)
322    * in native ALGLIB it returns current value of the allocation counter
323      (if it was activated)
324    ********************************************************************/
325    public static long alloc_counter()
326    {
327        return 0;
328    }
329   
330    /********************************************************************
331    Activization of the allocation counter:
332    * in managed ALGLIB it does nothing (dummy code)
333    * in native ALGLIB it turns on allocation counting.
334    ********************************************************************/
335    public static void alloc_counter_activate()
336    {
337    }
338   
339    /********************************************************************
340    This function allows to set one of the debug flags.
341    In managed ALGLIB does nothing (dummy).
342    ********************************************************************/
343    public static void set_dbg_flag(long flag_id, long flag_value)
344    {
345    }
346   
347    /********************************************************************
348    This function allows to get one of the debug counters.
349    In managed ALGLIB does nothing (dummy).
350    ********************************************************************/
351    public static long get_dbg_value(long id)
352    {
353        return 0;
354    }
355   
356    /********************************************************************
357    Activization of the allocation counter:
358    * in managed ALGLIB it does nothing (dummy code)
359    * in native ALGLIB it turns on allocation counting.
360    ********************************************************************/
361    public static void free_disposed_items()
362    {
363    }
364   
365    /************************************************************************
366    This function maps nworkers  number  (which  can  be  positive,  zero  or
367    negative with 0 meaning "all cores", -1 meaning "all cores -1" and so on)
368    to "effective", strictly positive workers count.
369
370    This  function  is  intended  to  be used by debugging/testing code which
371    tests different number of worker threads. It is NOT aligned  in  any  way
372    with ALGLIB multithreading framework (i.e. it can return  non-zero worker
373    count even for single-threaded GPLed ALGLIB).
374    ************************************************************************/
375    public static int get_effective_workers(int nworkers)
376    {
377        int ncores = System.Environment.ProcessorCount;
378        if( nworkers>=1 )
379            return nworkers>ncores ? ncores : nworkers;
380        return ncores+nworkers>=1 ? ncores+nworkers : 1;
381    }
382   
383    /********************************************************************
384    This function activates trace output, with trace log being  saved  to
385    file (appended to the end).
386
387    Tracing allows us to study behavior of ALGLIB solvers  and  to  debug
388    their failures:
389    * tracing is  limited  by one/several ALGLIB parts specified by means
390      of trace tags, like "SLP" (for SLP solver) or "OPTGUARD"  (OptGuard
391      integrity checker).
392    * some ALGLIB solvers support hierarchies of trace tags which activate
393      different kinds of tracing. Say, "SLP" defines some basic  tracing,
394      but "SLP.PROBING" defines more detailed and costly tracing.
395    * generally, "TRACETAG.SUBTAG"   also  implicitly  activates  logging
396      which is activated by "TRACETAG"
397    * you may define multiple trace tags by separating them with  commas,
398      like "SLP,OPTGUARD,SLP.PROBING"
399    * trace tags are case-insensitive
400    * spaces/tabs are NOT allowed in the tags string
401
402    Trace log is saved to file "filename", which is opened in the  append
403    mode. If no file with such name  can  be  opened,  tracing  won't  be
404    performed (but no exception will be generated).
405    ********************************************************************/
406    public static void trace_file(string tags, string filename)
407    {
408        ap.trace_file(tags, filename);
409    }
410   
411    /********************************************************************
412    This function disables tracing.
413    ********************************************************************/
414    public static void trace_disable()
415    {
416        ap.trace_disable();
417    }
418   
419    /********************************************************************
420    reverse communication structure
421    ********************************************************************/
422    public class rcommstate : apobject
423    {
424        public rcommstate()
425        {
426            init();
427        }
428        public override void init()
429        {
430            stage = -1;
431            ia = new int[0];
432            ba = new bool[0];
433            ra = new double[0];
434            ca = new alglib.complex[0];
435        }
436        public override apobject make_copy()
437        {
438            rcommstate result = new rcommstate();
439            result.stage = stage;
440            result.ia = (int[])ia.Clone();
441            result.ba = (bool[])ba.Clone();
442            result.ra = (double[])ra.Clone();
443            result.ca = (alglib.complex[])ca.Clone();
444            return result;
445        }
446        public int stage;
447        public int[] ia;
448        public bool[] ba;
449        public double[] ra;
450        public alglib.complex[] ca;
451    };
452
453    /********************************************************************
454    internal functions
455    ********************************************************************/
456    public class ap
457    {
458        public static int len<T>(T[] a)
459        { return a.Length; }
460        public static int rows<T>(T[,] a)
461        { return a.GetLength(0); }
462        public static int cols<T>(T[,] a)
463        { return a.GetLength(1); }
464        public static void swap<T>(ref T a, ref T b)
465        {
466            T t = a;
467            a = b;
468            b = t;
469        }
470       
471        public static void assert(bool cond, string s)
472        {
473            if( !cond )
474            {
475                if( trace_mode!=TRACE_MODE.NONE )
476                    trace("---!!! CRITICAL ERROR !!!--- exception with message '"+s+"' was generated\n");
477                throw new alglibexception(s);
478            }
479        }
480       
481        public static void assert(bool cond)
482        {
483            assert(cond, "ALGLIB: assertion failed");
484        }
485       
486        /****************************************************************
487        Error tracking for unit testing purposes; utility functions.
488        ****************************************************************/
489        public static string sef_xdesc = "";
490       
491        public static void seterrorflag(ref bool flag, bool cond, string xdesc)
492        {
493            if( cond )
494            {
495                flag = true;
496                sef_xdesc = xdesc;
497            }
498        }
499       
500        /****************************************************************
501        returns dps (digits-of-precision) value corresponding to threshold.
502        dps(0.9)  = dps(0.5)  = dps(0.1) = 0
503        dps(0.09) = dps(0.05) = dps(0.01) = 1
504        and so on
505        ****************************************************************/
506        public static int threshold2dps(double threshold)
507        {
508            int result = 0;
509            double t;
510            for (result = 0, t = 1; t / 10 > threshold*(1+1E-10); result++, t /= 10) ;
511            return result;
512        }
513
514        /****************************************************************
515        prints formatted complex
516        ****************************************************************/
517        public static string format(complex a, int _dps)
518        {
519            int dps = Math.Abs(_dps);
520            string fmt = _dps>=0 ? "F" : "E";
521            string fmtx = String.Format("{{0:"+fmt+"{0}}}", dps);
522            string fmty = String.Format("{{0:"+fmt+"{0}}}", dps);
523            string result = String.Format(fmtx, a.x) + (a.y >= 0 ? "+" : "-") + String.Format(fmty, Math.Abs(a.y)) + "i";
524            result = result.Replace(',', '.');
525            return result;
526        }
527
528        /****************************************************************
529        prints formatted array
530        ****************************************************************/
531        public static string format(bool[] a)
532        {
533            string[] result = new string[len(a)];
534            int i;
535            for(i=0; i<len(a); i++)
536                if( a[i] )
537                    result[i] = "true";
538                else
539                    result[i] = "false";
540            return "{"+String.Join(",",result)+"}";
541        }
542       
543        /****************************************************************
544        prints formatted array
545        ****************************************************************/
546        public static string format(int[] a)
547        {
548            string[] result = new string[len(a)];
549            int i;
550            for (i = 0; i < len(a); i++)
551                result[i] = a[i].ToString();
552            return "{" + String.Join(",", result) + "}";
553        }
554
555        /****************************************************************
556        prints formatted array
557        ****************************************************************/
558        public static string format(double[] a, int _dps)
559        {
560            int dps = Math.Abs(_dps);
561            string sfmt = _dps >= 0 ? "F" : "E";
562            string fmt = String.Format("{{0:" + sfmt + "{0}}}", dps);
563            string[] result = new string[len(a)];
564            int i;
565            for (i = 0; i < len(a); i++)
566            {
567                result[i] = String.Format(fmt, a[i]);
568                result[i] = result[i].Replace(',', '.');
569            }
570            return "{" + String.Join(",", result) + "}";
571        }
572
573        /****************************************************************
574        prints formatted array
575        ****************************************************************/
576        public static string format(complex[] a, int _dps)
577        {
578            int dps = Math.Abs(_dps);
579            string fmt = _dps >= 0 ? "F" : "E";
580            string fmtx = String.Format("{{0:"+fmt+"{0}}}", dps);
581            string fmty = String.Format("{{0:"+fmt+"{0}}}", dps);
582            string[] result = new string[len(a)];
583            int i;
584            for (i = 0; i < len(a); i++)
585            {
586                result[i] = String.Format(fmtx, a[i].x) + (a[i].y >= 0 ? "+" : "-") + String.Format(fmty, Math.Abs(a[i].y)) + "i";
587                result[i] = result[i].Replace(',', '.');
588            }
589            return "{" + String.Join(",", result) + "}";
590        }
591
592        /****************************************************************
593        prints formatted matrix
594        ****************************************************************/
595        public static string format(bool[,] a)
596        {
597            int i, j, m, n;
598            n = cols(a);
599            m = rows(a);
600            bool[] line = new bool[n];
601            string[] result = new string[m];
602            for (i = 0; i < m; i++)
603            {
604                for (j = 0; j < n; j++)
605                    line[j] = a[i, j];
606                result[i] = format(line);
607            }
608            return "{" + String.Join(",", result) + "}";
609        }
610
611        /****************************************************************
612        prints formatted matrix
613        ****************************************************************/
614        public static string format(int[,] a)
615        {
616            int i, j, m, n;
617            n = cols(a);
618            m = rows(a);
619            int[] line = new int[n];
620            string[] result = new string[m];
621            for (i = 0; i < m; i++)
622            {
623                for (j = 0; j < n; j++)
624                    line[j] = a[i, j];
625                result[i] = format(line);
626            }
627            return "{" + String.Join(",", result) + "}";
628        }
629
630        /****************************************************************
631        prints formatted matrix
632        ****************************************************************/
633        public static string format(double[,] a, int dps)
634        {
635            int i, j, m, n;
636            n = cols(a);
637            m = rows(a);
638            double[] line = new double[n];
639            string[] result = new string[m];
640            for (i = 0; i < m; i++)
641            {
642                for (j = 0; j < n; j++)
643                    line[j] = a[i, j];
644                result[i] = format(line, dps);
645            }
646            return "{" + String.Join(",", result) + "}";
647        }
648
649        /****************************************************************
650        prints formatted matrix
651        ****************************************************************/
652        public static string format(complex[,] a, int dps)
653        {
654            int i, j, m, n;
655            n = cols(a);
656            m = rows(a);
657            complex[] line = new complex[n];
658            string[] result = new string[m];
659            for (i = 0; i < m; i++)
660            {
661                for (j = 0; j < n; j++)
662                    line[j] = a[i, j];
663                result[i] = format(line, dps);
664            }
665            return "{" + String.Join(",", result) + "}";
666        }
667
668        /****************************************************************
669        checks that matrix is symmetric.
670        max|A-A^T| is calculated; if it is within 1.0E-14 of max|A|,
671        matrix is considered symmetric
672        ****************************************************************/
673        public static bool issymmetric(double[,] a)
674        {
675            int i, j, n;
676            double err, mx, v1, v2;
677            if( rows(a)!=cols(a) )
678                return false;
679            n = rows(a);
680            if( n==0 )
681                return true;
682            mx = 0;
683            err = 0;
684            for( i=0; i<n; i++)
685            {
686                for(j=i+1; j<n; j++)
687                {
688                    v1 = a[i,j];
689                    v2 = a[j,i];
690                    if( !math.isfinite(v1) )
691                        return false;
692                    if( !math.isfinite(v2) )
693                        return false;
694                    err = Math.Max(err, Math.Abs(v1-v2));
695                    mx  = Math.Max(mx,  Math.Abs(v1));
696                    mx  = Math.Max(mx,  Math.Abs(v2));
697                }
698                v1 = a[i,i];
699                if( !math.isfinite(v1) )
700                    return false;
701                mx = Math.Max(mx, Math.Abs(v1));
702            }
703            if( mx==0 )
704                return true;
705            return err/mx<=1.0E-14;
706        }
707       
708        /****************************************************************
709        checks that matrix is Hermitian.
710        max|A-A^H| is calculated; if it is within 1.0E-14 of max|A|,
711        matrix is considered Hermitian
712        ****************************************************************/
713        public static bool ishermitian(complex[,] a)
714        {
715            int i, j, n;
716            double err, mx;
717            complex v1, v2, vt;
718            if( rows(a)!=cols(a) )
719                return false;
720            n = rows(a);
721            if( n==0 )
722                return true;
723            mx = 0;
724            err = 0;
725            for( i=0; i<n; i++)
726            {
727                for(j=i+1; j<n; j++)
728                {
729                    v1 = a[i,j];
730                    v2 = a[j,i];
731                    if( !math.isfinite(v1.x) )
732                        return false;
733                    if( !math.isfinite(v1.y) )
734                        return false;
735                    if( !math.isfinite(v2.x) )
736                        return false;
737                    if( !math.isfinite(v2.y) )
738                        return false;
739                    vt.x = v1.x-v2.x;
740                    vt.y = v1.y+v2.y;
741                    err = Math.Max(err, math.abscomplex(vt));
742                    mx  = Math.Max(mx,  math.abscomplex(v1));
743                    mx  = Math.Max(mx,  math.abscomplex(v2));
744                }
745                v1 = a[i,i];
746                if( !math.isfinite(v1.x) )
747                    return false;
748                if( !math.isfinite(v1.y) )
749                    return false;
750                err = Math.Max(err, Math.Abs(v1.y));
751                mx = Math.Max(mx, math.abscomplex(v1));
752            }
753            if( mx==0 )
754                return true;
755            return err/mx<=1.0E-14;
756        }
757       
758       
759        /****************************************************************
760        Forces symmetricity by copying upper half of A to the lower one
761        ****************************************************************/
762        public static bool forcesymmetric(double[,] a)
763        {
764            int i, j, n;
765            if( rows(a)!=cols(a) )
766                return false;
767            n = rows(a);
768            if( n==0 )
769                return true;
770            for( i=0; i<n; i++)
771                for(j=i+1; j<n; j++)
772                    a[i,j] = a[j,i];
773            return true;
774        }
775       
776        /****************************************************************
777        Forces Hermiticity by copying upper half of A to the lower one
778        ****************************************************************/
779        public static bool forcehermitian(complex[,] a)
780        {
781            int i, j, n;
782            complex v;
783            if( rows(a)!=cols(a) )
784                return false;
785            n = rows(a);
786            if( n==0 )
787                return true;
788            for( i=0; i<n; i++)
789                for(j=i+1; j<n; j++)
790                {
791                    v = a[j,i];
792                    a[i,j].x = v.x;
793                    a[i,j].y = -v.y;
794                }
795            return true;
796        }
797       
798        /********************************************************************
799        Tracing and logging
800        ********************************************************************/
801        enum TRACE_MODE { NONE, FILE };
802        private static TRACE_MODE trace_mode = TRACE_MODE.NONE;
803        private static string trace_tags = "";
804        private static string trace_filename = "";
805       
806        public static void trace_file(string tags, string filename)
807        {
808            trace_mode     = TRACE_MODE.FILE;
809            trace_tags     = ","+tags.ToLower()+",";
810            trace_filename = filename;
811            trace("####################################################################################################\n");
812            trace("# TRACING ENABLED: "+System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+"\n");
813            trace("# TRACE TAGS:      '"+tags+"'\n");
814            trace("####################################################################################################\n");
815        }
816       
817        public static void trace_disable()
818        {
819            trace_mode     = TRACE_MODE.NONE;
820            trace_tags     = "";
821        }
822       
823        public static bool istraceenabled(string tag, xparams _params)
824        {
825            // trace disabled
826            if( trace_mode==TRACE_MODE.NONE )
827                return false;
828           
829            // contains tag (followed by comma, which means exact match)
830            if( trace_tags.Contains(","+tag.ToLower()+",") )
831                return true;
832           
833            // contains tag (followed by dot, which means match with child)
834            if( trace_tags.Contains(","+tag.ToLower()+".") )
835                return true;
836           
837            // nothing
838            return false;
839        }
840       
841        public static void trace(string s)
842        {
843            if( trace_mode==TRACE_MODE.NONE )
844                return;
845            if( trace_mode==TRACE_MODE.FILE )
846            {
847                System.IO.File.AppendAllText(trace_filename,s);
848                return;
849            }
850        }
851    };
852   
853    /********************************************************************
854    math functions
855    ********************************************************************/
856    public class math
857    {
858        //public static System.Random RndObject = new System.Random(System.DateTime.Now.Millisecond);
859        [ThreadStatic]  //mkommend: added thread static attribute to RNG to have a separate instance per thread and allow modification of the seed
860        public static System.Random rndobject = new System.Random(System.DateTime.Now.Millisecond + 1000*System.DateTime.Now.Second + 60*1000*System.DateTime.Now.Minute);
861
862        public const double machineepsilon = 5E-16;
863        public const double maxrealnumber = 1E300;
864        public const double minrealnumber = 1E-300;
865       
866        public static bool isfinite(double d)
867        {
868            return !System.Double.IsNaN(d) && !System.Double.IsInfinity(d);
869        }
870       
871        public static double randomreal()
872        {
873            double r = 0;
874            if (rndobject == null) rndobject = new System.Random(System.DateTime.Now.Millisecond + 1000 * System.DateTime.Now.Second + 60 * 1000 * System.DateTime.Now.Minute);
875            lock (rndobject){ r = rndobject.NextDouble(); }
876            return r;
877        }
878        public static int randominteger(int N)
879        {
880            int r = 0;
881            if (rndobject == null) rndobject = new System.Random(System.DateTime.Now.Millisecond + 1000 * System.DateTime.Now.Second + 60 * 1000 * System.DateTime.Now.Minute);
882            lock (rndobject){ r = rndobject.Next(N); }
883            return r;
884        }
885        public static double sqr(double X)
886        {
887            return X*X;
888        }       
889        public static double abscomplex(complex z)
890        {
891            double w;
892            double xabs;
893            double yabs;
894            double v;
895   
896            xabs = System.Math.Abs(z.x);
897            yabs = System.Math.Abs(z.y);
898            w = xabs>yabs ? xabs : yabs;
899            v = xabs<yabs ? xabs : yabs;
900            if( v==0 )
901                return w;
902            else
903            {
904                double t = v/w;
905                return w*System.Math.Sqrt(1+t*t);
906            }
907        }
908        public static complex conj(complex z)
909        {
910            return new complex(z.x, -z.y);
911        }   
912        public static complex csqr(complex z)
913        {
914            return new complex(z.x*z.x-z.y*z.y, 2*z.x*z.y);
915        }
916
917    }
918
919    /*
920     * CSV functionality
921     */
922     
923    public static int CSV_DEFAULT      = 0x0;
924    public static int CSV_SKIP_HEADERS = 0x1;
925   
926    /*
927     * CSV operations: reading CSV file to real matrix.
928     *
929     * This function reads CSV  file  and  stores  its  contents  to  double
930     * precision 2D array. Format of the data file must conform to RFC  4180
931     * specification, with additional notes:
932     * - file size should be less than 2GB
933     * - ASCI encoding, UTF-8 without BOM (in header names) are supported
934     * - any character (comma/tab/space) may be used as field separator,  as
935     *   long as it is distinct from one used for decimal point
936     * - multiple subsequent field separators (say, two  spaces) are treated
937     *   as MULTIPLE separators, not one big separator
938     * - both comma and full stop may be used as decimal point. Parser  will
939     *   automatically determine specific character being used.  Both  fixed
940     *   and exponential number formats are  allowed.   Thousand  separators
941     *   are NOT allowed.
942     * - line may end with \n (Unix style) or \r\n (Windows  style),  parser
943     *   will automatically adapt to chosen convention
944     * - escaped fields (ones in double quotes) are not supported
945     *
946     * INPUT PARAMETERS:
947     *     filename        relative/absolute path
948     *     separator       character used to separate fields.  May  be  ' ',
949     *                     ',', '\t'. Other separators are possible too.
950     *     flags           several values combined with bitwise OR:
951     *                     * alglib::CSV_SKIP_HEADERS -  if present, first row
952     *                       contains headers  and  will  be  skipped.   Its
953     *                       contents is used to determine fields count, and
954     *                       that's all.
955     *                     If no flags are specified, default value 0x0  (or
956     *                     alglib::CSV_DEFAULT, which is same) should be used.
957     *                     
958     * OUTPUT PARAMETERS:
959     *     out             2D matrix, CSV file parsed with atof()
960     *     
961     * HANDLING OF SPECIAL CASES:
962     * - file does not exist - alglib::ap_error exception is thrown
963     * - empty file - empty array is returned (no exception)
964     * - skip_first_row=true, only one row in file - empty array is returned
965     * - field contents is not recognized by atof() - field value is replaced
966     *   by 0.0
967     */
968    public static void read_csv(string filename, char separator, int flags, out double[,] matrix)
969    {
970        //
971        // Parameters
972        //
973        bool skip_first_row = (flags&CSV_SKIP_HEADERS)!=0;
974       
975        //
976        // Prepare empty output array
977        //
978        matrix = new double[0,0];
979       
980        //
981        // Read file, normalize file contents:
982        // * replace 0x0 by spaces
983        // * remove trailing spaces and newlines
984        // * append trailing '\n' and '\0' characters
985        // Return if file contains only spaces/newlines.
986        //
987        byte b_space = System.Convert.ToByte(' ');
988        byte b_tab   = System.Convert.ToByte('\t');
989        byte b_lf    = System.Convert.ToByte('\n');
990        byte b_cr    = System.Convert.ToByte('\r');
991        byte b_comma = System.Convert.ToByte(',');
992        byte b_fullstop= System.Convert.ToByte('.');
993        byte[] v0 = System.IO.File.ReadAllBytes(filename);
994        if( v0.Length==0 )
995            return;
996        byte[] v1 = new byte[v0.Length+2];
997        int filesize = v0.Length;
998        for(int i=0; i<filesize; i++)
999            v1[i] = v0[i]==0 ? b_space : v0[i];
1000        for(; filesize>0; )
1001        {
1002            byte c = v1[filesize-1];
1003            if( c==b_space || c==b_tab || c==b_cr || c==b_lf )
1004            {
1005                filesize--;
1006                continue;
1007            }
1008            break;
1009        }
1010        if( filesize==0 )
1011            return;
1012        v1[filesize+0] = b_lf;
1013        v1[filesize+1] = 0x0;
1014        filesize+=2;
1015       
1016       
1017        //
1018        // Scan dataset.
1019        //
1020        int rows_count, cols_count, max_length = 0;
1021        cols_count = 1;
1022        for(int idx=0; idx<filesize; idx++)
1023        {
1024            if( v1[idx]==separator )
1025                cols_count++;
1026            if( v1[idx]==b_lf )
1027                break;
1028        }
1029        rows_count = 0;
1030        for(int idx=0; idx<filesize; idx++)
1031            if( v1[idx]==b_lf )
1032                rows_count++;
1033        if( rows_count==1 && skip_first_row ) // empty output, return
1034            return;
1035        int[] offsets = new int[rows_count*cols_count];
1036        int[] lengths = new int[rows_count*cols_count];
1037        int cur_row_idx = 0;
1038        for(int row_start=0; v1[row_start]!=0x0; )
1039        {
1040            // determine row length
1041            int row_length;
1042            for(row_length=0; v1[row_start+row_length]!=b_lf; row_length++);
1043           
1044            // determine cols count, perform integrity check
1045            int cur_cols_cnt=1;
1046            for(int idx=0; idx<row_length; idx++)
1047                if( v1[row_start+idx]==separator )
1048                    cur_cols_cnt++;
1049            if( cols_count!=cur_cols_cnt )
1050                throw new alglib.alglibexception("read_csv: non-rectangular contents, rows have different sizes");
1051           
1052            // store offsets and lengths of the fields
1053            int cur_offs = 0;
1054            int cur_col_idx = 0;
1055            for(int idx=0; idx<row_length+1; idx++)
1056                if( v1[row_start+idx]==separator || v1[row_start+idx]==b_lf )
1057                {
1058                    offsets[cur_row_idx*cols_count+cur_col_idx] = row_start+cur_offs;
1059                    lengths[cur_row_idx*cols_count+cur_col_idx] = idx-cur_offs;
1060                    max_length = idx-cur_offs>max_length ? idx-cur_offs : max_length;
1061                    cur_offs = idx+1;
1062                    cur_col_idx++;
1063                }
1064           
1065            // advance row start
1066            cur_row_idx++;
1067            row_start = row_start+row_length+1;
1068        }
1069       
1070        //
1071        // Convert
1072        //
1073        int row0 = skip_first_row ? 1 : 0;
1074        int row1 = rows_count;
1075        System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture(""); // invariant culture
1076        matrix = new double[row1-row0, cols_count];
1077        alglib.AE_CRITICAL_ASSERT(culture.NumberFormat.NumberDecimalSeparator==".");
1078        for(int ridx=row0; ridx<row1; ridx++)
1079            for(int cidx=0; cidx<cols_count; cidx++)
1080            {
1081                int field_len  = lengths[ridx*cols_count+cidx];
1082                int field_offs = offsets[ridx*cols_count+cidx];
1083               
1084                // replace , by full stop
1085                for(int idx=0; idx<field_len; idx++)
1086                    if( v1[field_offs+idx]==b_comma )
1087                        v1[field_offs+idx] = b_fullstop;
1088               
1089                // convert
1090                string s_val = System.Text.Encoding.ASCII.GetString(v1, field_offs, field_len);
1091                double d_val;
1092                Double.TryParse(s_val, System.Globalization.NumberStyles.Float, culture, out d_val);
1093                matrix[ridx-row0,cidx] = d_val;
1094            }
1095    }
1096   
1097   
1098    /********************************************************************
1099    serializer object (should not be used directly)
1100    ********************************************************************/
1101    public class serializer
1102    {
1103        enum SMODE { DEFAULT, ALLOC, TO_STRING, FROM_STRING, TO_STREAM, FROM_STREAM };
1104        private const int SER_ENTRIES_PER_ROW = 5;
1105        private const int SER_ENTRY_LENGTH    = 11;
1106       
1107        private SMODE mode;
1108        private int entries_needed;
1109        private int entries_saved;
1110        private int bytes_asked;
1111        private int bytes_written;
1112        private int bytes_read;
1113        private char[] out_str;
1114        private char[] in_str;
1115        private System.IO.Stream io_stream;
1116       
1117        // local temporaries
1118        private char[] entry_buf_char;
1119        private byte[] entry_buf_byte;
1120       
1121        public serializer()
1122        {
1123            mode = SMODE.DEFAULT;
1124            entries_needed = 0;
1125            bytes_asked = 0;
1126            entry_buf_byte = new byte[SER_ENTRY_LENGTH+2];
1127            entry_buf_char = new char[SER_ENTRY_LENGTH+2];
1128        }
1129
1130        public void clear_buffers()
1131        {
1132            out_str = null;
1133            in_str = null;
1134            io_stream = null;
1135        }
1136
1137        public void alloc_start()
1138        {
1139            entries_needed = 0;
1140            bytes_asked = 0;
1141            mode = SMODE.ALLOC;
1142        }
1143
1144        public void alloc_entry()
1145        {
1146            if( mode!=SMODE.ALLOC )
1147                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1148            entries_needed++;
1149        }
1150
1151        public void alloc_byte_array(byte[] a)
1152        {
1153            if( mode!=SMODE.ALLOC )
1154                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1155            int n = ap.len(a);
1156            n = n/8 + (n%8>0 ? 1 : 0);
1157            entries_needed += 1+n;
1158        }
1159
1160        private int get_alloc_size()
1161        {
1162            int rows, lastrowsize, result;
1163           
1164            // check and change mode
1165            if( mode!=SMODE.ALLOC )
1166                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1167           
1168            // if no entries needes (degenerate case)
1169            if( entries_needed==0 )
1170            {
1171                bytes_asked = 4; /* a pair of chars for \r\n, one for space, one for dot */
1172                return bytes_asked;
1173            }
1174           
1175            // non-degenerate case
1176            rows = entries_needed/SER_ENTRIES_PER_ROW;
1177            lastrowsize = SER_ENTRIES_PER_ROW;
1178            if( entries_needed%SER_ENTRIES_PER_ROW!=0 )
1179            {
1180                lastrowsize = entries_needed%SER_ENTRIES_PER_ROW;
1181                rows++;
1182            }
1183           
1184            // calculate result size
1185            result  = ((rows-1)*SER_ENTRIES_PER_ROW+lastrowsize)*SER_ENTRY_LENGTH;  /* data size */
1186            result +=  (rows-1)*(SER_ENTRIES_PER_ROW-1)+(lastrowsize-1);            /* space symbols */
1187            result += rows*2;                                                       /* newline symbols */
1188            result += 1;                                                            /* trailing dot */
1189            bytes_asked = result;
1190            return result;
1191        }
1192
1193        public void sstart_str()
1194        {
1195            int allocsize = get_alloc_size();
1196           
1197            // clear input/output buffers which may hold pointers to unneeded memory
1198            // NOTE: it also helps us to avoid errors when data are written to incorrect location
1199            clear_buffers();
1200           
1201            // check and change mode
1202            if( mode!=SMODE.ALLOC )
1203                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1204            mode = SMODE.TO_STRING;
1205           
1206            // other preparations
1207            out_str = new char[allocsize];
1208            entries_saved = 0;
1209            bytes_written = 0;
1210        }
1211
1212        public void sstart_stream(System.IO.Stream o_stream)
1213        {   
1214            // clear input/output buffers which may hold pointers to unneeded memory
1215            // NOTE: it also helps us to avoid errors when data are written to incorrect location
1216            clear_buffers();
1217           
1218            // check and change mode
1219            if( mode!=SMODE.ALLOC )
1220                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1221            mode = SMODE.TO_STREAM;
1222            io_stream = o_stream;
1223        }
1224
1225        public void ustart_str(string s)
1226        {
1227            // clear input/output buffers which may hold pointers to unneeded memory
1228            // NOTE: it also helps us to avoid errors when data are written to incorrect location
1229            clear_buffers();
1230           
1231            // check and change mode
1232            if( mode!=SMODE.DEFAULT )
1233                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1234            mode = SMODE.FROM_STRING;
1235           
1236            in_str = s.ToCharArray();
1237            bytes_read = 0;
1238        }
1239
1240        public void ustart_stream(System.IO.Stream i_stream)
1241        {
1242            // clear input/output buffers which may hold pointers to unneeded memory
1243            // NOTE: it also helps us to avoid errors when data are written to incorrect location
1244            clear_buffers();
1245           
1246            // check and change mode
1247            if( mode!=SMODE.DEFAULT )
1248                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1249            mode = SMODE.FROM_STREAM;
1250            io_stream = i_stream;
1251        }
1252
1253        private void serialize_value(bool v0, int v1, double v2, ulong v3, int val_idx)
1254        {
1255            // prepare serialization
1256            char[] arr_out = null;
1257            int cnt_out = 0;
1258            if( mode==SMODE.TO_STRING )
1259            {
1260                arr_out = out_str;
1261                cnt_out = bytes_written;
1262            }
1263            else if( mode==SMODE.TO_STREAM )
1264            {
1265                arr_out = entry_buf_char;
1266                cnt_out = 0;
1267            }
1268            else
1269                throw new alglib.alglibexception("ALGLIB: internal error during serialization");
1270           
1271            // serialize
1272            if( val_idx==0 )
1273                bool2str(  v0, arr_out, ref cnt_out);
1274            else if( val_idx==1 )
1275                int2str(   v1, arr_out, ref cnt_out);
1276            else if( val_idx==2 )
1277                double2str(v2, arr_out, ref cnt_out);
1278            else if( val_idx==3 )
1279                ulong2str( v3, arr_out, ref cnt_out);
1280            else
1281                throw new alglib.alglibexception("ALGLIB: internal error during serialization");
1282            entries_saved++;
1283            if( entries_saved%SER_ENTRIES_PER_ROW!=0 )
1284            {
1285                arr_out[cnt_out] = ' ';
1286                cnt_out++;
1287            }
1288            else
1289            {
1290                arr_out[cnt_out+0] = '\r';
1291                arr_out[cnt_out+1] = '\n';
1292                cnt_out+=2;
1293            }
1294           
1295            // post-process
1296            if( mode==SMODE.TO_STRING )
1297            {
1298                bytes_written = cnt_out;
1299                return;
1300            }
1301            else if( mode==SMODE.TO_STREAM )
1302            {
1303                for(int k=0; k<cnt_out; k++)
1304                    entry_buf_byte[k] = (byte)entry_buf_char[k];
1305                io_stream.Write(entry_buf_byte, 0, cnt_out);
1306                return;
1307            }
1308            else
1309                throw new alglib.alglibexception("ALGLIB: internal error during serialization");
1310        }
1311
1312        private void unstream_entry_char()
1313        {
1314            if( mode!=SMODE.FROM_STREAM )
1315                throw new alglib.alglibexception("ALGLIB: internal error during unserialization");
1316            int c;
1317            for(;;)
1318            {
1319                c = io_stream.ReadByte();
1320                if( c<0 )
1321                    throw new alglib.alglibexception("ALGLIB: internal error during unserialization");
1322                if( c!=' ' && c!='\t' && c!='\n' && c!='\r' )
1323                    break;
1324            }
1325            entry_buf_char[0] = (char)c;
1326            for(int k=1; k<SER_ENTRY_LENGTH; k++)
1327            {
1328                c = io_stream.ReadByte();
1329                entry_buf_char[k] = (char)c;
1330                if( c<0 || c==' ' || c=='\t' || c=='\n' || c=='\r' )
1331                    throw new alglib.alglibexception("ALGLIB: internal error during unserialization");
1332            }
1333            entry_buf_char[SER_ENTRY_LENGTH] = (char)0;
1334        }
1335
1336        public void serialize_bool(bool v)
1337        {
1338            serialize_value(v, 0, 0, 0, 0);
1339        }
1340
1341        public void serialize_int(int v)
1342        {
1343            serialize_value(false, v, 0, 0, 1);
1344        }
1345
1346        public void serialize_double(double v)
1347        {
1348            serialize_value(false, 0, v, 0, 2);
1349        }
1350
1351        public void serialize_ulong(ulong v)
1352        {
1353            serialize_value(false, 0, 0, v, 3);
1354        }
1355
1356        public void serialize_byte_array(byte[] v)
1357        {
1358            int chunk_size = 8;
1359           
1360            // save array length
1361            int n = ap.len(v);
1362            serialize_int(n);
1363           
1364            // determine entries count
1365            int entries_count = n/chunk_size + (n%chunk_size>0 ? 1 : 0);
1366            for(int eidx=0; eidx<entries_count; eidx++)
1367            {
1368                int elen = n-eidx*chunk_size;
1369                elen = elen>chunk_size ? chunk_size : elen;
1370                ulong tmp = 0x0;
1371                for(int i=0; i<elen; i++)
1372                    tmp = tmp | (((ulong)v[eidx*chunk_size+i])<<(8*i));
1373                serialize_ulong(tmp);
1374            }
1375        }
1376
1377        public bool unserialize_bool()
1378        {
1379            if( mode==SMODE.FROM_STRING )
1380                return str2bool(in_str, ref bytes_read);
1381            if( mode==SMODE.FROM_STREAM )
1382            {
1383                unstream_entry_char();
1384                int dummy = 0;
1385                return str2bool(entry_buf_char, ref dummy);
1386            }
1387            throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1388        }
1389
1390        public int unserialize_int()
1391        {
1392            if( mode==SMODE.FROM_STRING )
1393                return str2int(in_str, ref bytes_read);
1394            if( mode==SMODE.FROM_STREAM )
1395            {
1396                unstream_entry_char();
1397                int dummy = 0;
1398                return str2int(entry_buf_char, ref dummy);
1399            }
1400            throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1401        }
1402
1403        public double unserialize_double()
1404        {
1405            if( mode==SMODE.FROM_STRING )
1406                return str2double(in_str, ref bytes_read);
1407            if( mode==SMODE.FROM_STREAM )
1408            {
1409                unstream_entry_char();
1410                int dummy = 0;
1411                return str2double(entry_buf_char, ref dummy);
1412            }
1413            throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1414        }
1415
1416        public ulong unserialize_ulong()
1417        {
1418            if( mode==SMODE.FROM_STRING )
1419                return str2ulong(in_str, ref bytes_read);
1420            if( mode==SMODE.FROM_STREAM )
1421            {
1422                unstream_entry_char();
1423                int dummy = 0;
1424                return str2ulong(entry_buf_char, ref dummy);
1425            }
1426            throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1427        }
1428
1429        public byte[] unserialize_byte_array()
1430        {
1431            int chunk_size = 8;
1432           
1433            // read array length, allocate output
1434            int n = unserialize_int();
1435            byte[] result = new byte[n];
1436           
1437            // determine entries count
1438            int entries_count = n/chunk_size + (n%chunk_size>0 ? 1 : 0);
1439            for(int eidx=0; eidx<entries_count; eidx++)
1440            {
1441                int elen = n-eidx*chunk_size;
1442                elen = elen>chunk_size ? chunk_size : elen;
1443                ulong tmp = unserialize_ulong();
1444                for(int i=0; i<elen; i++)
1445                    result[eidx*chunk_size+i] = unchecked((byte)(tmp>>(8*i)));
1446            }
1447           
1448            // done
1449            return result;
1450        }
1451
1452        public void stop()
1453        {
1454            if( mode==SMODE.TO_STRING )
1455            {
1456                out_str[bytes_written] = '.';
1457                bytes_written++;
1458                return;
1459            }
1460            if( mode==SMODE.FROM_STRING )
1461            {
1462                //
1463                // because input string may be from pre-3.11 serializer,
1464                // which does not include trailing dot, we do not test
1465                // string for presence of "." symbol. Anyway, because string
1466                // is not stream, we do not have to read ALL trailing symbols.
1467                //
1468                return;
1469            }
1470            if( mode==SMODE.TO_STREAM )
1471            {
1472                io_stream.WriteByte((byte)'.');
1473                return;
1474            }
1475            if( mode==SMODE.FROM_STREAM )
1476            {
1477                for(;;)
1478                {
1479                    int c = io_stream.ReadByte();
1480                    if( c==' ' || c=='\t' || c=='\n' || c=='\r' )
1481                        continue;
1482                    if( c=='.' )
1483                        break;
1484                    throw new alglib.alglibexception("ALGLIB: internal error during unserialization");
1485                }
1486                return;
1487            }
1488            throw new alglib.alglibexception("ALGLIB: internal error during unserialization");
1489        }
1490
1491        public string get_string()
1492        {
1493            if( mode!=SMODE.TO_STRING )
1494                throw new alglib.alglibexception("ALGLIB: internal error during (un)serialization");
1495             return new string(out_str, 0, bytes_written);
1496        }
1497
1498
1499        /************************************************************************
1500        This function converts six-bit value (from 0 to 63)  to  character  (only
1501        digits, lowercase and uppercase letters, minus and underscore are used).
1502
1503        If v is negative or greater than 63, this function returns '?'.
1504        ************************************************************************/
1505        private static char[] _sixbits2char_tbl = new char[64]{
1506                '0', '1', '2', '3', '4', '5', '6', '7',
1507                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1508                'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1509                'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1510                'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
1511                'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
1512                'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
1513                'u', 'v', 'w', 'x', 'y', 'z', '-', '_' };
1514        private static char sixbits2char(int v)
1515        {
1516            if( v<0 || v>63 )
1517                return '?';
1518            return _sixbits2char_tbl[v];
1519        }
1520       
1521        /************************************************************************
1522        This function converts character to six-bit value (from 0 to 63).
1523
1524        This function is inverse of ae_sixbits2char()
1525        If c is not correct character, this function returns -1.
1526        ************************************************************************/
1527        private static int[] _char2sixbits_tbl = new int[128] {
1528            -1, -1, -1, -1, -1, -1, -1, -1,
1529            -1, -1, -1, -1, -1, -1, -1, -1,
1530            -1, -1, -1, -1, -1, -1, -1, -1,
1531            -1, -1, -1, -1, -1, -1, -1, -1,
1532            -1, -1, -1, -1, -1, -1, -1, -1,
1533            -1, -1, -1, -1, -1, 62, -1, -1,
1534             0,  1,  2,  3,  4,  5,  6,  7,
1535             8,  9, -1, -1, -1, -1, -1, -1,
1536            -1, 10, 11, 12, 13, 14, 15, 16,
1537            17, 18, 19, 20, 21, 22, 23, 24,
1538            25, 26, 27, 28, 29, 30, 31, 32,
1539            33, 34, 35, -1, -1, -1, -1, 63,
1540            -1, 36, 37, 38, 39, 40, 41, 42,
1541            43, 44, 45, 46, 47, 48, 49, 50,
1542            51, 52, 53, 54, 55, 56, 57, 58,
1543            59, 60, 61, -1, -1, -1, -1, -1 };
1544        private static int char2sixbits(char c)
1545        {
1546            return (c>=0 && c<127) ? _char2sixbits_tbl[c] : -1;
1547        }
1548       
1549        /************************************************************************
1550        This function converts three bytes (24 bits) to four six-bit values
1551        (24 bits again).
1552
1553        src         array
1554        src_offs    offset of three-bytes chunk
1555        dst         array for ints
1556        dst_offs    offset of four-ints chunk
1557        ************************************************************************/
1558        private static void threebytes2foursixbits(byte[] src, int src_offs, int[] dst, int dst_offs)
1559        {
1560            dst[dst_offs+0] =  src[src_offs+0] & 0x3F;
1561            dst[dst_offs+1] = (src[src_offs+0]>>6) | ((src[src_offs+1]&0x0F)<<2);
1562            dst[dst_offs+2] = (src[src_offs+1]>>4) | ((src[src_offs+2]&0x03)<<4);
1563            dst[dst_offs+3] =  src[src_offs+2]>>2;
1564        }
1565
1566        /************************************************************************
1567        This function converts four six-bit values (24 bits) to three bytes
1568        (24 bits again).
1569
1570        src         pointer to four ints
1571        src_offs    offset of the chunk
1572        dst         pointer to three bytes
1573        dst_offs    offset of the chunk
1574        ************************************************************************/
1575        private static void foursixbits2threebytes(int[] src, int src_offs, byte[] dst, int dst_offs)
1576        {
1577            dst[dst_offs+0] =      (byte)(src[src_offs+0] | ((src[src_offs+1]&0x03)<<6));
1578            dst[dst_offs+1] = (byte)((src[src_offs+1]>>2) | ((src[src_offs+2]&0x0F)<<4));
1579            dst[dst_offs+2] = (byte)((src[src_offs+2]>>4) |  (src[src_offs+3]<<2));
1580        }
1581
1582        /************************************************************************
1583        This function serializes boolean value into buffer
1584
1585        v           boolean value to be serialized
1586        buf         buffer, at least 11 characters wide
1587        offs        offset in the buffer
1588       
1589        after return from this function, offs points to the char's past the value
1590        being read.
1591        ************************************************************************/
1592        private static void bool2str(bool v, char[] buf, ref int offs)
1593        {
1594            char c = v ? '1' : '0';
1595            int i;
1596            for(i=0; i<SER_ENTRY_LENGTH; i++)
1597                buf[offs+i] = c;
1598            offs += SER_ENTRY_LENGTH;
1599        }
1600
1601        /************************************************************************
1602        This function unserializes boolean value from buffer
1603
1604        buf         buffer which contains value; leading spaces/tabs/newlines are
1605                    ignored, traling spaces/tabs/newlines are treated as  end  of
1606                    the boolean value.
1607        offs        offset in the buffer
1608       
1609        after return from this function, offs points to the char's past the value
1610        being read.
1611
1612        This function raises an error in case unexpected symbol is found
1613        ************************************************************************/
1614        private static bool str2bool(char[] buf, ref int offs)
1615        {
1616            bool was0, was1;
1617            string emsg = "ALGLIB: unable to read boolean value from stream";
1618           
1619            was0 = false;
1620            was1 = false;
1621            while( buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r' )
1622                offs++;
1623            while( buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0 )
1624            {
1625                if( buf[offs]=='0' )
1626                {
1627                    was0 = true;
1628                    offs++;
1629                    continue;
1630                }
1631                if( buf[offs]=='1' )
1632                {
1633                    was1 = true;
1634                    offs++;
1635                    continue;
1636                }
1637                throw new alglib.alglibexception(emsg);
1638            }
1639            if( (!was0) && (!was1) )
1640                throw new alglib.alglibexception(emsg);
1641            if( was0 && was1 )
1642                throw new alglib.alglibexception(emsg);
1643            return was1 ? true : false;
1644        }
1645
1646        /************************************************************************
1647        This function serializes integer value into buffer
1648
1649        v           integer value to be serialized
1650        buf         buffer, at least 11 characters wide
1651        offs        offset in the buffer
1652       
1653        after return from this function, offs points to the char's past the value
1654        being read.
1655
1656        This function raises an error in case unexpected symbol is found
1657        ************************************************************************/
1658        private static void int2str(int v, char[] buf, ref int offs)
1659        {
1660            int i;
1661            byte[] _bytes = System.BitConverter.GetBytes((int)v);
1662            byte[]  bytes = new byte[9];
1663            int[] sixbits = new int[12];
1664            byte c;
1665           
1666            //
1667            // copy v to array of bytes, sign extending it and
1668            // converting to little endian order. Additionally,
1669            // we set 9th byte to zero in order to simplify
1670            // conversion to six-bit representation
1671            //
1672            if( !System.BitConverter.IsLittleEndian )
1673                System.Array.Reverse(_bytes);
1674            c = v<0 ? (byte)0xFF : (byte)0x00;
1675            for(i=0; i<sizeof(int); i++)
1676                bytes[i] = _bytes[i];
1677            for(i=sizeof(int); i<8; i++)
1678                bytes[i] = c;
1679            bytes[8] = 0;
1680           
1681            //
1682            // convert to six-bit representation, output
1683            //
1684            // NOTE: last 12th element of sixbits is always zero, we do not output it
1685            //
1686            threebytes2foursixbits(bytes, 0, sixbits, 0);
1687            threebytes2foursixbits(bytes, 3, sixbits, 4);
1688            threebytes2foursixbits(bytes, 6, sixbits, 8);       
1689            for(i=0; i<SER_ENTRY_LENGTH; i++)
1690                buf[offs+i] = sixbits2char(sixbits[i]);
1691            offs += SER_ENTRY_LENGTH;
1692        }
1693
1694        /************************************************************************
1695        This function unserializes integer value from string
1696
1697        buf         buffer which contains value; leading spaces/tabs/newlines are
1698                    ignored, traling spaces/tabs/newlines are treated as  end  of
1699                    the integer value.
1700        offs        offset in the buffer
1701       
1702        after return from this function, offs points to the char's past the value
1703        being read.
1704
1705        This function raises an error in case unexpected symbol is found
1706        ************************************************************************/
1707        private static int str2int(char[] buf, ref int offs)
1708        {
1709            string emsg =       "ALGLIB: unable to read integer value from stream";
1710            string emsg3264 =   "ALGLIB: unable to read integer value from stream (value does not fit into 32 bits)";
1711            int[] sixbits = new int[12];
1712            byte[] bytes = new byte[9];
1713            byte[] _bytes = new byte[sizeof(int)];
1714            int sixbitsread, i;
1715            byte c;
1716           
1717            //
1718            // 1. skip leading spaces
1719            // 2. read and decode six-bit digits
1720            // 3. set trailing digits to zeros
1721            // 4. convert to little endian 64-bit integer representation
1722            // 5. check that we fit into int
1723            // 6. convert to big endian representation, if needed
1724            //
1725            sixbitsread = 0;
1726            while( buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r' )
1727                offs++;
1728            while( buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0 )
1729            {
1730                int d;
1731                d = char2sixbits(buf[offs]);
1732                if( d<0 || sixbitsread>=SER_ENTRY_LENGTH )
1733                    throw new alglib.alglibexception(emsg);
1734                sixbits[sixbitsread] = d;
1735                sixbitsread++;
1736                offs++;
1737            }
1738            if( sixbitsread==0 )
1739                throw new alglib.alglibexception(emsg);
1740            for(i=sixbitsread; i<12; i++)
1741                sixbits[i] = 0;
1742            foursixbits2threebytes(sixbits, 0, bytes, 0);
1743            foursixbits2threebytes(sixbits, 4, bytes, 3);
1744            foursixbits2threebytes(sixbits, 8, bytes, 6);
1745            c = (bytes[sizeof(int)-1] & 0x80)!=0 ? (byte)0xFF : (byte)0x00;
1746            for(i=sizeof(int); i<8; i++)
1747                if( bytes[i]!=c )
1748                    throw new alglib.alglibexception(emsg3264);
1749            for(i=0; i<sizeof(int); i++)
1750                _bytes[i] = bytes[i];       
1751            if( !System.BitConverter.IsLittleEndian )
1752                System.Array.Reverse(_bytes);
1753            return System.BitConverter.ToInt32(_bytes,0);
1754        }
1755       
1756       
1757        /************************************************************************
1758        This function serializes double value into buffer
1759
1760        v           double value to be serialized
1761        buf         buffer, at least 11 characters wide
1762        offs        offset in the buffer
1763       
1764        after return from this function, offs points to the char's past the value
1765        being read.
1766        ************************************************************************/
1767        private static void double2str(double v, char[] buf, ref int offs)
1768        {
1769            int i;
1770            int[] sixbits = new int[12];
1771            byte[] bytes = new byte[9];
1772
1773            //
1774            // handle special quantities
1775            //
1776            if( System.Double.IsNaN(v) )
1777            {
1778                buf[offs+0] = '.';
1779                buf[offs+1] = 'n';
1780                buf[offs+2] = 'a';
1781                buf[offs+3] = 'n';
1782                buf[offs+4] = '_';
1783                buf[offs+5] = '_';
1784                buf[offs+6] = '_';
1785                buf[offs+7] = '_';
1786                buf[offs+8] = '_';
1787                buf[offs+9] = '_';
1788                buf[offs+10] = '_';
1789                offs += SER_ENTRY_LENGTH;
1790                return;
1791            }
1792            if( System.Double.IsPositiveInfinity(v) )
1793            {
1794                buf[offs+0] = '.';
1795                buf[offs+1] = 'p';
1796                buf[offs+2] = 'o';
1797                buf[offs+3] = 's';
1798                buf[offs+4] = 'i';
1799                buf[offs+5] = 'n';
1800                buf[offs+6] = 'f';
1801                buf[offs+7] = '_';
1802                buf[offs+8] = '_';
1803                buf[offs+9] = '_';
1804                buf[offs+10] = '_';
1805                offs += SER_ENTRY_LENGTH;
1806                return;
1807            }
1808            if( System.Double.IsNegativeInfinity(v) )
1809            {
1810                buf[offs+0] = '.';
1811                buf[offs+1] = 'n';
1812                buf[offs+2] = 'e';
1813                buf[offs+3] = 'g';
1814                buf[offs+4] = 'i';
1815                buf[offs+5] = 'n';
1816                buf[offs+6] = 'f';
1817                buf[offs+7] = '_';
1818                buf[offs+8] = '_';
1819                buf[offs+9] = '_';
1820                buf[offs+10] = '_';
1821                offs += SER_ENTRY_LENGTH;
1822                return;
1823            }
1824           
1825            //
1826            // process general case:
1827            // 1. copy v to array of chars
1828            // 2. set 9th byte to zero in order to simplify conversion to six-bit representation
1829            // 3. convert to little endian (if needed)
1830            // 4. convert to six-bit representation
1831            //    (last 12th element of sixbits is always zero, we do not output it)
1832            //
1833            byte[] _bytes = System.BitConverter.GetBytes((double)v);
1834            if( !System.BitConverter.IsLittleEndian )
1835                System.Array.Reverse(_bytes);
1836            for(i=0; i<sizeof(double); i++)
1837                bytes[i] = _bytes[i];
1838            for(i=sizeof(double); i<9; i++)
1839                bytes[i] = 0;
1840            threebytes2foursixbits(bytes, 0, sixbits, 0);
1841            threebytes2foursixbits(bytes, 3, sixbits, 4);
1842            threebytes2foursixbits(bytes, 6, sixbits, 8);
1843            for(i=0; i<SER_ENTRY_LENGTH; i++)
1844                buf[offs+i] = sixbits2char(sixbits[i]);
1845            offs += SER_ENTRY_LENGTH;
1846        }
1847       
1848       
1849        /************************************************************************
1850        This function serializes ulong value into buffer
1851
1852        v           ulong value to be serialized
1853        buf         buffer, at least 11 characters wide
1854        offs        offset in the buffer
1855       
1856        after return from this function, offs points to the char's past the value
1857        being read.
1858        ************************************************************************/
1859        private static void ulong2str(ulong v, char[] buf, ref int offs)
1860        {
1861            int i;
1862            int[] sixbits = new int[12];
1863            byte[] bytes = new byte[9];
1864           
1865            //
1866            // process general case:
1867            // 1. copy v to array of chars
1868            // 2. set 9th byte to zero in order to simplify conversion to six-bit representation
1869            // 3. convert to little endian (if needed)
1870            // 4. convert to six-bit representation
1871            //    (last 12th element of sixbits is always zero, we do not output it)
1872            //
1873            byte[] _bytes = System.BitConverter.GetBytes((ulong)v);
1874            if( !System.BitConverter.IsLittleEndian )
1875                System.Array.Reverse(_bytes);
1876            for(i=0; i<sizeof(ulong); i++)
1877                bytes[i] = _bytes[i];
1878            for(i=sizeof(ulong); i<9; i++)
1879                bytes[i] = 0;
1880            threebytes2foursixbits(bytes, 0, sixbits, 0);
1881            threebytes2foursixbits(bytes, 3, sixbits, 4);
1882            threebytes2foursixbits(bytes, 6, sixbits, 8);
1883            for(i=0; i<SER_ENTRY_LENGTH; i++)
1884                buf[offs+i] = sixbits2char(sixbits[i]);
1885            offs += SER_ENTRY_LENGTH;
1886        }
1887
1888        /************************************************************************
1889        This function unserializes double value from string
1890
1891        buf         buffer which contains value; leading spaces/tabs/newlines are
1892                    ignored, traling spaces/tabs/newlines are treated as  end  of
1893                    the double value.
1894        offs        offset in the buffer
1895       
1896        after return from this function, offs points to the char's past the value
1897        being read.
1898
1899        This function raises an error in case unexpected symbol is found
1900        ************************************************************************/
1901        private static double str2double(char[] buf, ref int offs)
1902        {
1903            string emsg = "ALGLIB: unable to read double value from stream";
1904            int[] sixbits = new int[12];
1905            byte[]  bytes = new byte[9];
1906            byte[] _bytes = new byte[sizeof(double)];
1907            int sixbitsread, i;
1908           
1909           
1910            //
1911            // skip leading spaces
1912            //
1913            while( buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r' )
1914                offs++;
1915           
1916             
1917            //
1918            // Handle special cases
1919            //
1920            if( buf[offs]=='.' )
1921            {
1922                string s = new string(buf, offs, SER_ENTRY_LENGTH);
1923                if( s==".nan_______" )
1924                {
1925                    offs += SER_ENTRY_LENGTH;
1926                    return System.Double.NaN;
1927                }
1928                if( s==".posinf____" )
1929                {
1930                    offs += SER_ENTRY_LENGTH;
1931                    return System.Double.PositiveInfinity;
1932                }
1933                if( s==".neginf____" )
1934                {
1935                    offs += SER_ENTRY_LENGTH;
1936                    return System.Double.NegativeInfinity;
1937                }
1938                throw new alglib.alglibexception(emsg);
1939            }
1940           
1941            //
1942            // General case:
1943            // 1. read and decode six-bit digits
1944            // 2. check that all 11 digits were read
1945            // 3. set last 12th digit to zero (needed for simplicity of conversion)
1946            // 4. convert to 8 bytes
1947            // 5. convert to big endian representation, if needed
1948            //
1949            sixbitsread = 0;
1950            while( buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0 )
1951            {
1952                int d;
1953                d = char2sixbits(buf[offs]);
1954                if( d<0 || sixbitsread>=SER_ENTRY_LENGTH )
1955                    throw new alglib.alglibexception(emsg);
1956                sixbits[sixbitsread] = d;
1957                sixbitsread++;
1958                offs++;
1959            }
1960            if( sixbitsread!=SER_ENTRY_LENGTH )
1961                throw new alglib.alglibexception(emsg);
1962            sixbits[SER_ENTRY_LENGTH] = 0;
1963            foursixbits2threebytes(sixbits, 0, bytes, 0);
1964            foursixbits2threebytes(sixbits, 4, bytes, 3);
1965            foursixbits2threebytes(sixbits, 8, bytes, 6);
1966            for(i=0; i<sizeof(double); i++)
1967                _bytes[i] = bytes[i];       
1968            if( !System.BitConverter.IsLittleEndian )
1969                System.Array.Reverse(_bytes);       
1970            return System.BitConverter.ToDouble(_bytes,0);
1971        }
1972
1973        /************************************************************************
1974        This function unserializes ulong value from string
1975
1976        buf         buffer which contains value; leading spaces/tabs/newlines are
1977                    ignored, traling spaces/tabs/newlines are treated as  end  of
1978                    the ulong value.
1979        offs        offset in the buffer
1980       
1981        after return from this function, offs points to the char's past the value
1982        being read.
1983
1984        This function raises an error in case unexpected symbol is found
1985        ************************************************************************/
1986        private static ulong str2ulong(char[] buf, ref int offs)
1987        {
1988            string emsg = "ALGLIB: unable to read ulong value from stream";
1989            int[] sixbits = new int[12];
1990            byte[]  bytes = new byte[9];
1991            byte[] _bytes = new byte[sizeof(ulong)];
1992            int sixbitsread, i;
1993           
1994           
1995            //
1996            // skip leading spaces
1997            //
1998            while( buf[offs]==' ' || buf[offs]=='\t' || buf[offs]=='\n' || buf[offs]=='\r' )
1999                offs++;
2000           
2001            //
2002            // 1. read and decode six-bit digits
2003            // 2. check that all 11 digits were read
2004            // 3. set last 12th digit to zero (needed for simplicity of conversion)
2005            // 4. convert to 8 bytes
2006            // 5. convert to big endian representation, if needed
2007            //
2008            sixbitsread = 0;
2009            while( buf[offs]!=' ' && buf[offs]!='\t' && buf[offs]!='\n' && buf[offs]!='\r' && buf[offs]!=0 )
2010            {
2011                int d;
2012                d = char2sixbits(buf[offs]);
2013                if( d<0 || sixbitsread>=SER_ENTRY_LENGTH )
2014                    throw new alglib.alglibexception(emsg);
2015                sixbits[sixbitsread] = d;
2016                sixbitsread++;
2017                offs++;
2018            }
2019            if( sixbitsread!=SER_ENTRY_LENGTH )
2020                throw new alglib.alglibexception(emsg);
2021            sixbits[SER_ENTRY_LENGTH] = 0;
2022            foursixbits2threebytes(sixbits, 0, bytes, 0);
2023            foursixbits2threebytes(sixbits, 4, bytes, 3);
2024            foursixbits2threebytes(sixbits, 8, bytes, 6);
2025            for(i=0; i<sizeof(ulong); i++)
2026                _bytes[i] = bytes[i];       
2027            if( !System.BitConverter.IsLittleEndian )
2028                System.Array.Reverse(_bytes);       
2029            return System.BitConverter.ToUInt64(_bytes,0);
2030        }
2031    }
2032   
2033    /*
2034     * Parts of alglib.smp class which are shared with GPL version of ALGLIB
2035     */
2036    public partial class smp
2037    {
2038        #pragma warning disable 420
2039        public const int AE_LOCK_CYCLES = 512;
2040        public const int AE_LOCK_TESTS_BEFORE_YIELD = 16;
2041       
2042        /*
2043         * This variable is used to perform spin-wait loops in a platform-independent manner
2044         * (loops which should work same way on Mono and Microsoft NET). You SHOULD NEVER
2045         * change this field - it must be zero during all program life.
2046         */
2047        public static volatile int never_change_it = 0;
2048       
2049        /*************************************************************************
2050        Lock.
2051
2052        This class provides lightweight spin lock
2053        *************************************************************************/
2054        public class ae_lock
2055        {
2056            public volatile int is_locked;
2057        }
2058
2059        /********************************************************************
2060        Shared pool: data structure used to provide thread-safe access to pool
2061        of temporary variables.
2062        ********************************************************************/
2063        public class sharedpoolentry
2064        {
2065            public apobject obj;
2066            public sharedpoolentry next_entry;
2067        }
2068        public class shared_pool : apobject
2069        {
2070            /* lock object which protects pool */
2071            public ae_lock pool_lock;
2072   
2073            /* seed object (used to create new instances of temporaries) */
2074            public volatile apobject seed_object;
2075           
2076            /*
2077             * list of recycled OBJECTS:
2078             * 1. entries in this list store pointers to recycled objects
2079             * 2. every time we retrieve object, we retrieve first entry from this list,
2080             *    move it to recycled_entries and return its obj field to caller/
2081             */
2082            public volatile sharedpoolentry recycled_objects;
2083           
2084            /*
2085             * list of recycled ENTRIES:
2086             * 1. this list holds entries which are not used to store recycled objects;
2087             *    every time recycled object is retrieved, its entry is moved to this list.
2088             * 2. every time object is recycled, we try to fetch entry for him from this list
2089             *    before allocating it with malloc()
2090             */
2091            public volatile sharedpoolentry recycled_entries;
2092           
2093            /* enumeration pointer, points to current recycled object*/
2094            public volatile sharedpoolentry enumeration_counter;
2095           
2096            /* constructor */
2097            public shared_pool()
2098            {
2099                ae_init_lock(ref pool_lock);
2100            }
2101           
2102            /* initializer - creation of empty pool */
2103            public override void init()
2104            {
2105                seed_object = null;
2106                recycled_objects = null;
2107                recycled_entries = null;
2108                enumeration_counter = null;
2109            }
2110           
2111            /* copy constructor (it is NOT thread-safe) */
2112            public override apobject make_copy()
2113            {
2114                sharedpoolentry ptr, buf;
2115                shared_pool result = new shared_pool();
2116               
2117                /* create lock */
2118                ae_init_lock(ref result.pool_lock);
2119   
2120                /* copy seed object */
2121                if( seed_object!=null )
2122                    result.seed_object = seed_object.make_copy();
2123               
2124                /*
2125                 * copy recycled objects:
2126                 * 1. copy to temporary list (objects are inserted to beginning, order is reversed)
2127                 * 2. copy temporary list to output list (order is restored back to normal)
2128                 */
2129                buf = null;
2130                for(ptr=recycled_objects; ptr!=null; ptr=ptr.next_entry)
2131                {
2132                    sharedpoolentry tmp = new sharedpoolentry();
2133                    tmp.obj =  ptr.obj.make_copy();
2134                    tmp.next_entry = buf;
2135                    buf = tmp;
2136                }
2137                result.recycled_objects = null;
2138                for(ptr=buf; ptr!=null;)
2139                {
2140                    sharedpoolentry next_ptr = ptr.next_entry;
2141                    ptr.next_entry = result.recycled_objects;
2142                    result.recycled_objects = ptr;
2143                    ptr = next_ptr;
2144                }
2145   
2146                /* recycled entries are not copied because they do not store any information */
2147                result.recycled_entries = null;
2148   
2149                /* enumeration counter is reset on copying */
2150                result.enumeration_counter = null;
2151   
2152                return result;
2153            }
2154        }
2155       
2156
2157        /************************************************************************
2158        This function performs given number of spin-wait iterations
2159        ************************************************************************/
2160        public static void ae_spin_wait(int cnt)
2161        {
2162            /*
2163             * these strange operations with ae_never_change_it are necessary to
2164             * prevent compiler optimization of the loop.
2165             */
2166            int i;
2167           
2168            /* very unlikely because no one will wait for such amount of cycles */
2169            if( cnt>0x12345678 )
2170                never_change_it = cnt%10;
2171           
2172            /* spin wait, test condition which will never be true */
2173            for(i=0; i<cnt; i++)
2174                if( never_change_it>0 )
2175                    never_change_it--;
2176        }
2177
2178
2179        /************************************************************************
2180        This function causes the calling thread to relinquish the CPU. The thread
2181        is moved to the end of the queue and some other thread gets to run.
2182        ************************************************************************/
2183        public static void ae_yield()
2184        {
2185            System.Threading.Thread.Sleep(0);
2186        }
2187
2188        /************************************************************************
2189        This function initializes ae_lock structure and sets lock in a free mode.
2190        ************************************************************************/
2191        public static void ae_init_lock(ref ae_lock obj)
2192        {
2193            obj = new ae_lock();
2194            obj.is_locked = 0;
2195        }
2196
2197
2198        /************************************************************************
2199        This function acquires lock. In case lock is busy, we perform several
2200        iterations inside tight loop before trying again.
2201        ************************************************************************/
2202        public static void ae_acquire_lock(ae_lock obj)
2203        {
2204            int cnt = 0;
2205            for(;;)
2206            {
2207                if( System.Threading.Interlocked.CompareExchange(ref obj.is_locked, 1, 0)==0 )
2208                    return;
2209                ae_spin_wait(AE_LOCK_CYCLES);
2210                cnt++;
2211                if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 )
2212                    ae_yield();
2213            }
2214        }
2215
2216
2217        /************************************************************************
2218        This function releases lock.
2219        ************************************************************************/
2220        public static void ae_release_lock(ae_lock obj)
2221        {
2222            System.Threading.Interlocked.Exchange(ref obj.is_locked, 0);
2223        }
2224
2225
2226        /************************************************************************
2227        This function frees ae_lock structure.
2228        ************************************************************************/
2229        public static void ae_free_lock(ref ae_lock obj)
2230        {
2231            obj = null;
2232        }
2233       
2234       
2235        /************************************************************************
2236        This function returns True, if internal seed object was set.  It  returns
2237        False for un-seeded pool.
2238
2239        dst                 destination pool (initialized by constructor function)
2240
2241        NOTE: this function is NOT thread-safe. It does not acquire pool lock, so
2242              you should NOT call it when lock can be used by another thread.
2243        ************************************************************************/
2244        public static bool ae_shared_pool_is_initialized(shared_pool dst)
2245        {
2246            return dst.seed_object!=null;
2247        }
2248
2249
2250        /************************************************************************
2251        This function sets internal seed object. All objects owned by the pool
2252        (current seed object, recycled objects) are automatically freed.
2253
2254        dst                 destination pool (initialized by constructor function)
2255        seed_object         new seed object
2256
2257        NOTE: this function is NOT thread-safe. It does not acquire pool lock, so
2258              you should NOT call it when lock can be used by another thread.
2259        ************************************************************************/
2260        public static void ae_shared_pool_set_seed(shared_pool dst, alglib.apobject seed_object)
2261        {
2262            dst.seed_object = seed_object.make_copy();
2263            dst.recycled_objects = null;
2264            dst.enumeration_counter = null;
2265        }
2266
2267
2268        /************************************************************************
2269        This  function  retrieves  a  copy  of  the seed object from the pool and
2270        stores it to target variable.
2271
2272        pool                pool
2273        obj                 target variable
2274       
2275        NOTE: this function IS thread-safe.  It  acquires  pool  lock  during its
2276              operation and can be used simultaneously from several threads.
2277        ************************************************************************/
2278        public static void ae_shared_pool_retrieve<T>(shared_pool pool, ref T obj) where T : alglib.apobject
2279        {
2280            alglib.apobject new_obj;
2281           
2282            /* assert that pool was seeded */
2283            alglib.ap.assert(pool.seed_object!=null, "ALGLIB: shared pool is not seeded, PoolRetrieve() failed");
2284           
2285            /* acquire lock */
2286            ae_acquire_lock(pool.pool_lock);
2287           
2288            /* try to reuse recycled objects */
2289            if( pool.recycled_objects!=null )
2290            {
2291                /* retrieve entry/object from list of recycled objects */
2292                sharedpoolentry result = pool.recycled_objects;
2293                pool.recycled_objects = pool.recycled_objects.next_entry;
2294                new_obj = result.obj;
2295                result.obj = null;
2296               
2297                /* move entry to list of recycled entries */
2298                result.next_entry = pool.recycled_entries;
2299                pool.recycled_entries = result;
2300               
2301                /* release lock */
2302                ae_release_lock(pool.pool_lock);
2303               
2304                /* assign object to smart pointer */
2305                obj = (T)new_obj;
2306               
2307                return;
2308            }
2309               
2310            /*
2311             * release lock; we do not need it anymore because
2312             * copy constructor does not modify source variable.
2313             */
2314            ae_release_lock(pool.pool_lock);
2315           
2316            /* create new object from seed */
2317            new_obj = pool.seed_object.make_copy();
2318               
2319            /* assign object to pointer and return */
2320            obj = (T)new_obj;
2321        }
2322
2323
2324        /************************************************************************
2325        This  function  recycles object owned by the source variable by moving it
2326        to internal storage of the shared pool.
2327
2328        Source  variable  must  own  the  object,  i.e.  be  the only place where
2329        reference  to  object  is  stored.  After  call  to  this function source
2330        variable becomes NULL.
2331
2332        pool                pool
2333        obj                 source variable
2334
2335        NOTE: this function IS thread-safe.  It  acquires  pool  lock  during its
2336              operation and can be used simultaneously from several threads.
2337        ************************************************************************/
2338        public static void ae_shared_pool_recycle<T>(shared_pool pool, ref T obj) where T : alglib.apobject
2339        {
2340            sharedpoolentry new_entry;
2341           
2342            /* assert that pool was seeded */
2343            alglib.ap.assert(pool.seed_object!=null, "ALGLIB: shared pool is not seeded, PoolRecycle() failed");
2344           
2345            /* assert that pointer non-null */
2346            alglib.ap.assert(obj!=null, "ALGLIB: obj in ae_shared_pool_recycle() is NULL");
2347           
2348            /* acquire lock */
2349            ae_acquire_lock(pool.pool_lock);
2350           
2351            /* acquire shared pool entry (reuse one from recycled_entries or malloc new one) */
2352            if( pool.recycled_entries!=null )
2353            {
2354                /* reuse previously allocated entry */
2355                new_entry = pool.recycled_entries;
2356                pool.recycled_entries = new_entry.next_entry;
2357            }
2358            else
2359            {
2360                /*
2361                 * Allocate memory for new entry.
2362                 *
2363                 * NOTE: we release pool lock during allocation because new() may raise
2364                 *       exception and we do not want our pool to be left in the locked state.
2365                 */
2366                ae_release_lock(pool.pool_lock);
2367                new_entry = new sharedpoolentry();
2368                ae_acquire_lock(pool.pool_lock);
2369            }
2370           
2371            /* add object to the list of recycled objects */
2372            new_entry.obj = obj;
2373            new_entry.next_entry = pool.recycled_objects;
2374            pool.recycled_objects = new_entry;
2375           
2376            /* release lock object */
2377            ae_release_lock(pool.pool_lock);
2378           
2379            /* release source pointer */
2380            obj = null;
2381        }
2382
2383
2384        /************************************************************************
2385        This function clears internal list of  recycled  objects,  but  does  not
2386        change seed object managed by the pool.
2387
2388        pool                pool
2389
2390        NOTE: this function is NOT thread-safe. It does not acquire pool lock, so
2391              you should NOT call it when lock can be used by another thread.
2392        ************************************************************************/
2393        public static void ae_shared_pool_clear_recycled(shared_pool pool)
2394        {
2395            pool.recycled_objects = null;
2396        }
2397
2398
2399        /************************************************************************
2400        This function allows to enumerate recycled elements of the  shared  pool.
2401        It stores reference to the first recycled object in the smart pointer.
2402
2403        IMPORTANT:
2404        * in case target variable owns non-NULL value, it is rewritten
2405        * recycled object IS NOT removed from pool
2406        * target variable DOES NOT become owner of the new value; you can use
2407          reference to recycled object, but you do not own it.
2408        * this function IS NOT thread-safe
2409        * you SHOULD NOT modify shared pool during enumeration (although you  can
2410          modify state of the objects retrieved from pool)
2411        * in case there is no recycled objects in the pool, NULL is stored to obj
2412        * in case pool is not seeded, NULL is stored to obj
2413
2414        pool                pool
2415        obj                 reference
2416        ************************************************************************/
2417        public static void ae_shared_pool_first_recycled<T>(shared_pool pool, ref T obj) where T : alglib.apobject
2418        {   
2419            /* modify internal enumeration counter */
2420            pool.enumeration_counter = pool.recycled_objects;
2421           
2422            /* exit on empty list */
2423            if( pool.enumeration_counter==null )
2424            {
2425                obj = null;
2426                return;
2427            }
2428           
2429            /* assign object to smart pointer */
2430            obj = (T)pool.enumeration_counter.obj;
2431        }
2432
2433
2434        /************************************************************************
2435        This function allows to enumerate recycled elements of the  shared  pool.
2436        It stores pointer to the next recycled object in the smart pointer.
2437
2438        IMPORTANT:
2439        * in case target variable owns non-NULL value, it is rewritten
2440        * recycled object IS NOT removed from pool
2441        * target pointer DOES NOT become owner of the new value
2442        * this function IS NOT thread-safe
2443        * you SHOULD NOT modify shared pool during enumeration (although you  can
2444          modify state of the objects retrieved from pool)
2445        * in case there is no recycled objects left in the pool, NULL is stored.
2446        * in case pool is not seeded, NULL is stored.
2447
2448        pool                pool
2449        obj                 target variable
2450        ************************************************************************/
2451        public static void ae_shared_pool_next_recycled<T>(shared_pool pool, ref T obj) where T : alglib.apobject
2452        {   
2453            /* exit on end of list */
2454            if( pool.enumeration_counter==null )
2455            {
2456                obj = null;
2457                return;
2458            }
2459           
2460            /* modify internal enumeration counter */
2461            pool.enumeration_counter = pool.enumeration_counter.next_entry;
2462           
2463            /* exit on empty list */
2464            if( pool.enumeration_counter==null )
2465            {
2466                obj = null;
2467                return;
2468            }
2469           
2470            /* assign object to smart pointer */
2471            obj = (T)pool.enumeration_counter.obj;
2472        }
2473
2474
2475        /************************************************************************
2476        This function clears internal list of recycled objects and  seed  object.
2477        However, pool still can be used (after initialization with another seed).
2478
2479        pool                pool
2480        state               ALGLIB environment state
2481
2482        NOTE: this function is NOT thread-safe. It does not acquire pool lock, so
2483              you should NOT call it when lock can be used by another thread.
2484        ************************************************************************/
2485        public static void ae_shared_pool_reset(shared_pool pool)
2486        {   
2487            pool.seed_object = null;
2488            pool.recycled_objects = null;
2489            pool.enumeration_counter = null;
2490        }
2491    }
2492}
2493public partial class alglib
2494{
2495    public partial class smp
2496    {
2497        public static int cores_count = 1;
2498        public static volatile int cores_to_use = 1;
2499        public static bool isparallelcontext()
2500        {
2501            return false;
2502        }
2503    }
2504    public class smpselftests
2505    {
2506        public static bool runtests()
2507        {
2508            return true;
2509        }
2510    }
2511    public static void setnworkers(int nworkers)
2512    {
2513        alglib.smp.cores_to_use = nworkers;
2514    }
2515    public static int getnworkers()
2516    {
2517        return alglib.smp.cores_to_use;
2518    }
2519}
Note: See TracBrowser for help on using the repository browser.