Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/Predictor.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/Predictor.cs	(revision 2414)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/Predictor.cs	(revision 2415)
@@ -79,5 +79,5 @@
       Problem p = SVMHelper.CreateSVMProblem(input, input.GetVariableIndex(targetVariable), newIndex,
         start, end, minTimeOffset, maxTimeOffset);
-      Problem scaledProblem = SVM.Scaling.Scale(p, transform);
+      Problem scaledProblem = transform.Scale(p);
 
       int targetVariableIndex = input.GetVariableIndex(targetVariable);
@@ -155,4 +155,47 @@
       }
     }
+
+    public static void Export(Predictor p, Stream s) {
+      StreamWriter writer = new StreamWriter(s);
+      writer.Write("Targetvariable: "); writer.WriteLine(p.targetVariable);
+      writer.Write("LowerPredictionLimit: "); writer.WriteLine(p.LowerPredictionLimit.ToString());
+      writer.Write("UpperPredictionLimit: "); writer.WriteLine(p.UpperPredictionLimit.ToString());
+      writer.Write("MaxTimeOffset: "); writer.WriteLine(p.MaxTimeOffset.ToString());
+      writer.Write("MinTimeOffset: "); writer.WriteLine(p.MinTimeOffset.ToString());
+      writer.Write("InputVariables :");
+      writer.Write(p.GetInputVariables().First());
+      foreach (string variable in p.GetInputVariables().Skip(1)) {
+        writer.Write("; "); writer.Write(variable);
+      }
+      writer.WriteLine();
+      writer.Flush();
+      using (MemoryStream memStream = new MemoryStream()) {
+        SVMModel.Export(p.Model, memStream);
+        memStream.WriteTo(s);
+      }
+    }
+
+    public static Predictor Import(Stream s) {
+      Predictor p = new Predictor();
+      StreamReader reader = new StreamReader(s);
+      string[] targetVariableLine = reader.ReadLine().Split(':');
+      string[] lowerPredictionLimitLine = reader.ReadLine().Split(':');
+      string[] upperPredictionLimitLine = reader.ReadLine().Split(':');
+      string[] maxTimeOffsetLine = reader.ReadLine().Split(':');
+      string[] minTimeOffsetLine = reader.ReadLine().Split(':');
+      string[] inputVariableLine = reader.ReadLine().Split(':', ';');
+
+      p.targetVariable = targetVariableLine[1].Trim();
+      p.LowerPredictionLimit = double.Parse(lowerPredictionLimitLine[1]);
+      p.UpperPredictionLimit = double.Parse(upperPredictionLimitLine[1]);
+      p.maxTimeOffset = int.Parse(maxTimeOffsetLine[1]);
+      p.minTimeOffset = int.Parse(minTimeOffsetLine[1]);
+      int i = 1;
+      foreach (string inputVariable in inputVariableLine.Skip(1)) {
+        p.variableNames[inputVariable.Trim()] = i++;
+      }
+      p.svmModel = SVMModel.Import(s);
+      return p;
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/PredictorView.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/PredictorView.cs	(revision 2414)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/PredictorView.cs	(revision 2415)
@@ -29,4 +29,5 @@
 using System.Windows.Forms;
 using HeuristicLab.Core;
+using System.IO;
 
 namespace HeuristicLab.SupportVectorMachines {
@@ -50,18 +51,18 @@
     }
 
-    protected override string GetModelString() {
-      StringBuilder builder = new StringBuilder();
-      builder.Append("LowerPredictionLimit: ").AppendLine(predictor.LowerPredictionLimit.ToString());
-      builder.Append("UpperPredictionLimit: ").AppendLine(predictor.UpperPredictionLimit.ToString());
-      builder.Append("MaxTimeOffset: ").AppendLine(predictor.MaxTimeOffset.ToString());
-      builder.Append("MinTimeOffset: ").AppendLine(predictor.MinTimeOffset.ToString());
-      builder.Append("InputVariables :");
-      builder.Append(predictor.GetInputVariables().First());
-      foreach (string variable in predictor.GetInputVariables().Skip(1)) {
-        builder.Append("; ").Append(variable);
+    protected override void UpdateControls() {
+      base.UpdateControls();
+      textBox.Text = GetModelString();
+    }
+
+    private string GetModelString() {
+      if (predictor == null) return "";
+      using (MemoryStream s = new MemoryStream()) {
+        Predictor.Export(predictor, s);
+        s.Flush();
+        s.Seek(0, System.IO.SeekOrigin.Begin);
+        StreamReader reader = new StreamReader(s);
+        return reader.ReadToEnd();
       }
-      builder.AppendLine();
-      builder.Append(base.GetModelString());
-      return builder.ToString();
     }
   }
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SVMModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SVMModel.cs	(revision 2414)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SVMModel.cs	(revision 2415)
@@ -116,4 +116,34 @@
       }
     }
+
+    public static void Export(SVMModel model, Stream s) {
+      StreamWriter writer = new StreamWriter(s);
+      writer.WriteLine("RangeTransform:");
+      using (MemoryStream memStream = new MemoryStream()) {
+        SVM.RangeTransform.Write(memStream, model.RangeTransform);
+        memStream.Seek(0, SeekOrigin.Begin);
+        memStream.WriteTo(s);
+      }
+      writer.WriteLine("Model:");
+
+      using (MemoryStream memStream = new MemoryStream()) {
+        SVM.Model.Write(memStream, model.Model);
+        memStream.Seek(0, SeekOrigin.Begin);
+        memStream.WriteTo(s);
+      }
+      s.Flush();
+    }
+
+    public static SVMModel Import(Stream s) {
+      SVMModel model = new SVMModel();
+      StreamReader reader = new StreamReader(s);
+      while (reader.ReadLine().Trim() != "RangeTransform:") ; // read until line "RangeTransform";
+      model.RangeTransform = SVM.RangeTransform.Read(s);
+
+      // read until "Model:"
+      while (reader.ReadLine().Trim() != "Model:") ;
+      model.Model = SVM.Model.Read(s);
+      return model;
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SVMModelView.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SVMModelView.cs	(revision 2414)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SVMModelView.cs	(revision 2415)
@@ -49,4 +49,5 @@
       kernelType.DataBindings.Add(new Binding("Text", model.Model.Parameter, "KernelType"));
       gamma.DataBindings.Add(new Binding("Text", model.Model.Parameter, "Gamma"));
+      UpdateControls();
     }
 
@@ -56,21 +57,12 @@
     }
 
-    protected virtual string GetModelString() {
-      StringBuilder builder = new StringBuilder();
-      builder.AppendLine("RangeTransform:");
-      using (MemoryStream stream = new MemoryStream()) {
-        SVM.RangeTransform.Write(stream, model.RangeTransform);
-        stream.Seek(0, System.IO.SeekOrigin.Begin);
-        StreamReader reader = new StreamReader(stream);
-        builder.AppendLine(reader.ReadToEnd());
+    private string GetModelString() {
+      using (MemoryStream s = new MemoryStream()) {
+        SVMModel.Export(model, s);
+        s.Flush();
+        s.Seek(0, System.IO.SeekOrigin.Begin);
+        StreamReader reader = new StreamReader(s);
+        return reader.ReadToEnd();
       }
-      builder.AppendLine("Model:");
-      using (MemoryStream stream = new MemoryStream()) {
-        SVM.Model.Write(stream, model.Model);
-        stream.Seek(0, System.IO.SeekOrigin.Begin);
-        StreamReader reader = new StreamReader(stream);
-        builder.AppendLine(reader.ReadToEnd());
-      }
-      return builder.ToString();
     }
   }
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorCreator.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorCreator.cs	(revision 2414)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorCreator.cs	(revision 2415)
@@ -28,4 +28,5 @@
 using HeuristicLab.DataAnalysis;
 using System.Threading;
+using SVM;
 
 namespace HeuristicLab.SupportVectorMachines {
@@ -85,8 +86,10 @@
       parameter.Nu = GetVariableValue<DoubleData>("SVMNu", scope, true).Data;
       parameter.Gamma = GetVariableValue<DoubleData>("SVMGamma", scope, true).Data;
+      parameter.CacheSize = 500;
+      parameter.Probability = false;
 
       SVM.Problem problem = SVMHelper.CreateSVMProblem(dataset, targetVariable, start, end, minTimeOffset, maxTimeOffset);
-      SVM.RangeTransform rangeTransform = SVM.Scaling.DetermineRange(problem);
-      SVM.Problem scaledProblem = SVM.Scaling.Scale(problem, rangeTransform);
+      SVM.RangeTransform rangeTransform = SVM.RangeTransform.Compute(problem);
+      SVM.Problem scaledProblem = rangeTransform.Scale(problem);
 
       SVM.Model model = StartTraining(scaledProblem, parameter);
Index: /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorEvaluator.cs
===================================================================
--- /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorEvaluator.cs	(revision 2414)
+++ /trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorEvaluator.cs	(revision 2415)
@@ -27,4 +27,5 @@
 using HeuristicLab.Data;
 using HeuristicLab.DataAnalysis;
+using SVM;
 
 namespace HeuristicLab.SupportVectorMachines {
@@ -56,5 +57,5 @@
       SVMModel modelData = GetVariableValue<SVMModel>("SVMModel", scope, true);
       SVM.Problem problem = SVMHelper.CreateSVMProblem(dataset, targetVariable, start, end, minTimeOffset, maxTimeOffset);
-      SVM.Problem scaledProblem = SVM.Scaling.Scale(problem, modelData.RangeTransform);
+      SVM.Problem scaledProblem = modelData.RangeTransform.Scale(problem);
 
       double[,] values = new double[scaledProblem.Count, 2];
Index: /trunk/sources/LibSVM/Cache.cs
===================================================================
--- /trunk/sources/LibSVM/Cache.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Cache.cs	(revision 2415)
@@ -49,5 +49,5 @@
         private head_t lru_head;
 
-        internal Cache(int count, long size)
+        public Cache(int count, long size)
         {
             _count = count;
@@ -78,9 +78,16 @@
         }
 
+        private static void swap<T>(ref T lhs, ref T rhs)
+        {
+            T tmp = lhs;
+            lhs = rhs;
+            rhs = tmp;
+        }
+
         // request data [0,len)
         // return some position p where [p,len) need to be filled
         // (p >= len if nothing needs to be filled)
         // java: simulate pointer using single-element array
-        internal virtual int get_data(int index, float[][] data, int len)
+        public int GetData(int index, ref float[] data, int len)
         {
             head_t h = head[index];
@@ -107,17 +114,13 @@
                 h.data = new_data;
                 _size -= more;
-                do
-                {
-                    int _ = h.len; h.len = len; len = _;
-                }
-                while (false);
+                swap(ref h.len, ref len);
             }
 
             lru_insert(h);
-            data[0] = h.data;
+            data = h.data;
             return len;
         }
 
-        internal virtual void swap_index(int i, int j)
+        public void SwapIndex(int i, int j)
         {
             if (i == j)
@@ -128,14 +131,6 @@
             if (head[j].len > 0)
                 lru_delete(head[j]);
-            do
-            {
-                float[] _ = head[i].data; head[i].data = head[j].data; head[j].data = _;
-            }
-            while (false);
-            do
-            {
-                int _ = head[i].len; head[i].len = head[j].len; head[j].len = _;
-            }
-            while (false);
+            swap(ref head[i].data, ref head[j].data);
+            swap(ref head[i].len, ref head[j].len);
             if (head[i].len > 0)
                 lru_insert(head[i]);
@@ -144,9 +139,6 @@
 
             if (i > j)
-                do
-                {
-                    int _ = i; i = j; j = _;
-                }
-                while (false);
+                swap(ref i, ref j);
+
             for (head_t h = lru_head.next; h != lru_head; h = h.next)
             {
@@ -154,9 +146,5 @@
                 {
                     if (h.len > j)
-                        do
-                        {
-                            float _ = h.data[i]; h.data[i] = h.data[j]; h.data[j] = _;
-                        }
-                        while (false);
+                        swap(ref h.data[i], ref h.data[j]);
                     else
                     {
Index: /trunk/sources/LibSVM/GaussianTransform.cs
===================================================================
--- /trunk/sources/LibSVM/GaussianTransform.cs	(revision 2414)
+++ /trunk/sources/LibSVM/GaussianTransform.cs	(revision 2415)
@@ -21,82 +21,71 @@
 using System.Collections.Generic;
 using System.IO;
+using System.Globalization;
+using System.Threading;
 
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// A transform which learns the mean and variance of a sample set and uses these to transform new data
     /// so that it has zero mean and unit variance.
-    /// </remarks>
+    /// </summary>
     public class GaussianTransform : IRangeTransform
     {
-        private List<Node[]> _samples;
-        private int _maxIndex;
-
         private double[] _means;
         private double[] _stddevs;
 
         /// <summary>
+        /// Determines the Gaussian transform for the provided problem.
+        /// </summary>
+        /// <param name="prob">The Problem to analyze</param>
+        /// <returns>The Gaussian transform for the problem</returns>
+        public static GaussianTransform Compute(Problem prob)
+        {
+            int[] counts = new int[prob.MaxIndex];
+            double[] means = new double[prob.MaxIndex];
+            foreach (Node[] sample in prob.X)
+            {
+                for (int i = 0; i < sample.Length; i++)
+                {
+                    means[sample[i].Index-1] += sample[i].Value;
+                    counts[sample[i].Index-1]++;
+                }
+            }
+            for (int i = 0; i < prob.MaxIndex; i++)
+            {
+                if (counts[i] == 0)
+                    counts[i] = 2;
+                means[i] /= counts[i];
+            }
+
+            double[] stddevs = new double[prob.MaxIndex];
+            foreach (Node[] sample in prob.X)
+            {
+                for (int i = 0; i < sample.Length; i++)
+                {
+                    double diff = sample[i].Value - means[sample[i].Index - 1];
+                    stddevs[sample[i].Index - 1] += diff * diff;
+                }
+            }
+            for (int i = 0; i < prob.MaxIndex; i++)
+            {
+                if (stddevs[i] == 0)
+                    continue;
+                stddevs[i] /= (counts[i] - 1);
+                stddevs[i] = Math.Sqrt(stddevs[i]);
+            }
+
+            return new GaussianTransform(means, stddevs);
+        }
+
+        /// <summary>
         /// Constructor.
         /// </summary>
-        /// <param name="maxIndex">The maximum index of the vectors to be transformed</param>
-        public GaussianTransform(int maxIndex)
-        {
-            _samples = new List<Node[]>();
-        }
-        private GaussianTransform(double[] means, double[] stddevs, int maxIndex)
+        /// <param name="means">Means in each dimension</param>
+        /// <param name="stddevs">Standard deviation in each dimension</param>
+        public GaussianTransform(double[] means, double[] stddevs)
         {
             _means = means;
             _stddevs = stddevs;
-            _maxIndex = maxIndex;
-        }
-
-        /// <summary>
-        /// Adds a sample to the data.  No computation is performed.  The maximum index of the
-        /// sample must be less than MaxIndex.
-        /// </summary>
-        /// <param name="sample">The sample to add</param>
-        public void Add(Node[] sample)
-        {
-            _samples.Add(sample);
-        }
-
-        /// <summary>
-        /// Computes the statistics for the samples which have been obtained so far.
-        /// </summary>
-        public void ComputeStatistics()
-        {
-            int[] counts = new int[_maxIndex];
-            _means = new double[_maxIndex];
-            foreach(Node[] sample in _samples)
-            {
-                for (int i = 0; i < sample.Length; i++)
-                {
-                    _means[sample[i].Index] += sample[i].Value;
-                    counts[sample[i].Index]++;
-                }
-            }
-            for (int i = 0; i < _maxIndex; i++)
-            {
-                if (counts[i] == 0)
-                    counts[i] = 2;
-                _means[i] /= counts[i];
-            }
-
-            _stddevs = new double[_maxIndex];
-            foreach(Node[] sample in _samples)
-            {
-                for (int i = 0; i < sample.Length; i++)
-                {
-                    double diff = sample[i].Value - _means[sample[i].Index];
-                    _stddevs[sample[i].Index] += diff * diff;
-                }
-            }
-            for (int i = 0; i < _maxIndex; i++)
-            {
-                if (_stddevs[i] == 0)
-                    continue;
-                _stddevs[i] /= (counts[i]-1);
-                _stddevs[i] = Math.Sqrt(_stddevs[i]);
-            }
         }
 
@@ -109,9 +98,13 @@
         public static void Write(Stream stream, GaussianTransform transform)
         {
+            TemporaryCulture.Start();
+
             StreamWriter output = new StreamWriter(stream);
-            output.WriteLine(transform._maxIndex);
-            for (int i = 0; i < transform._maxIndex; i++)
+            output.WriteLine(transform._means.Length);
+            for (int i = 0; i < transform._means.Length; i++)
                 output.WriteLine("{0} {1}", transform._means[i], transform._stddevs[i]);
             output.Flush();
+
+            TemporaryCulture.Stop();
         }
 
@@ -123,6 +116,8 @@
         public static GaussianTransform Read(Stream stream)
         {
+            TemporaryCulture.Start();
+
             StreamReader input = new StreamReader(stream);
-            int length = int.Parse(input.ReadLine());
+            int length = int.Parse(input.ReadLine(), CultureInfo.InvariantCulture);
             double[] means = new double[length];
             double[] stddevs = new double[length];
@@ -130,8 +125,11 @@
             {
                 string[] parts = input.ReadLine().Split();
-                means[i] = double.Parse(parts[0]);
-                stddevs[i] = double.Parse(parts[1]);
-            }
-            return new GaussianTransform(means, stddevs, length);
+                means[i] = double.Parse(parts[0], CultureInfo.InvariantCulture);
+                stddevs[i] = double.Parse(parts[1], CultureInfo.InvariantCulture);
+            }
+
+            TemporaryCulture.Stop();
+
+            return new GaussianTransform(means, stddevs);
         }
 
@@ -177,6 +175,4 @@
         /// <summary>
         /// Transform the input value using the transform stored for the provided index.
-        /// <see cref="ComputeStatistics"/> must be called first, or the transform must
-        /// have been read from the disk.
         /// </summary>
         /// <param name="input">Input value</param>
@@ -185,4 +181,5 @@
         public double Transform(double input, int index)
         {
+            index--;
             if (_stddevs[index] == 0)
                 return 0;
@@ -192,6 +189,5 @@
         }
         /// <summary>
-        /// Transforms the input array.  <see cref="ComputeStatistics"/> must be called 
-        /// first, or the transform must have been read from the disk.
+        /// Transforms the input array.
         /// </summary>
         /// <param name="input">The array to transform</param>
Index: /trunk/sources/LibSVM/IRangeTransform.cs
===================================================================
--- /trunk/sources/LibSVM/IRangeTransform.cs	(revision 2414)
+++ /trunk/sources/LibSVM/IRangeTransform.cs	(revision 2415)
@@ -20,7 +20,7 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Interface implemented by range transforms.
-    /// </remarks>
+    /// </summary>
     public interface IRangeTransform
     {
Index: /trunk/sources/LibSVM/Kernel.cs
===================================================================
--- /trunk/sources/LibSVM/Kernel.cs	(revision 2415)
+++ /trunk/sources/LibSVM/Kernel.cs	(revision 2415)
@@ -0,0 +1,226 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SVM
+{
+    internal interface IQMatrix
+    {
+        float[] GetQ(int column, int len);
+        float[] GetQD();
+        void SwapIndex(int i, int j);
+    }
+
+    internal abstract class Kernel : IQMatrix
+    {
+        private Node[][] _x;
+        private double[] _xSquare;
+
+        private KernelType _kernelType;
+        private int _degree;
+        private double _gamma;
+        private double _coef0;
+
+        public abstract float[] GetQ(int column, int len);
+        public abstract float[] GetQD();
+
+        public virtual void SwapIndex(int i, int j)
+        {
+            _x.SwapIndex(i, j);
+
+            if (_xSquare != null)
+            {
+                _xSquare.SwapIndex(i, j);
+            }
+        }
+
+        private static double powi(double value, int times)
+        {
+            double tmp = value, ret = 1.0;
+
+            for (int t = times; t > 0; t /= 2)
+            {
+                if (t % 2 == 1) ret *= tmp;
+                tmp = tmp * tmp;
+            }
+            return ret;
+        }
+
+        public double KernelFunction(int i, int j)
+        {
+            switch (_kernelType)
+            {
+                case KernelType.LINEAR:
+                    return dot(_x[i], _x[j]);
+                case KernelType.POLY:
+                    return powi(_gamma * dot(_x[i], _x[j]) + _coef0, _degree);
+                case KernelType.RBF:
+                    return Math.Exp(-_gamma * (_xSquare[i] + _xSquare[j] - 2 * dot(_x[i], _x[j])));
+                case KernelType.SIGMOID:
+                    return Math.Tanh(_gamma * dot(_x[i], _x[j]) + _coef0);
+                case KernelType.PRECOMPUTED:
+                    return _x[i][(int)(_x[j][0].Value)].Value;
+                default:
+                    return 0;
+            }
+        }
+
+        public Kernel(int l, Node[][] x_, Parameter param)
+        {
+            _kernelType = param.KernelType;
+            _degree = param.Degree;
+            _gamma = param.Gamma;
+            _coef0 = param.Coefficient0;
+
+            _x = (Node[][])x_.Clone();
+
+            if (_kernelType == KernelType.RBF)
+            {
+                _xSquare = new double[l];
+                for (int i = 0; i < l; i++)
+                    _xSquare[i] = dot(_x[i], _x[i]);
+            }
+            else _xSquare = null;
+        }
+
+        private static double dot(Node[] xNodes, Node[] yNodes)
+        {
+            double sum = 0;
+            int xlen = xNodes.Length;
+            int ylen = yNodes.Length;
+            int i = 0;
+            int j = 0;
+            Node x = xNodes[0];
+            Node y = yNodes[0];
+            while (true)
+            {
+                if (x._index == y._index)
+                {
+                    sum += x._value * y._value;
+                    i++;
+                    j++;
+                    if (i < xlen && j < ylen)
+                    {
+                        x = xNodes[i];
+                        y = yNodes[j];
+                    }
+                    else if (i < xlen)
+                    {
+                        x = xNodes[i];
+                        break;
+                    }
+                    else if (j < ylen)
+                    {
+                        y = yNodes[j];
+                        break;
+                    }
+                    else break;
+                }
+                else
+                {
+                    if (x._index > y._index)
+                    {
+                        ++j;
+                        if (j < ylen)
+                            y = yNodes[j];
+                        else break;
+                    }
+                    else
+                    {
+                        ++i;
+                        if (i < xlen)
+                            x = xNodes[i];
+                        else break;
+                    }
+                }
+            }
+            return sum;
+        }
+
+        private static double computeSquaredDistance(Node[] xNodes, Node[] yNodes)
+        {
+            Node x = xNodes[0];
+            Node y = yNodes[0];
+            int xLength = xNodes.Length;
+            int yLength = yNodes.Length;
+            int xIndex = 0;
+            int yIndex = 0;
+            double sum = 0;
+
+            while (true)
+            {
+                if (x._index == y._index)
+                {
+                    double d = x._value - y._value;
+                    sum += d * d;
+                    xIndex++;
+                    yIndex++;
+                    if (xIndex < xLength && yIndex < yLength)
+                    {
+                        x = xNodes[xIndex];
+                        y = yNodes[yIndex];
+                    }
+                    else if(xIndex < xLength){
+                        x = xNodes[xIndex];
+                        break;
+                    }
+                    else if(yIndex < yLength){
+                        y = yNodes[yIndex];
+                        break;
+                    }else break;
+                }
+                else if (x._index > y._index)
+                {
+                    sum += y._value * y._value;
+                    if (++yIndex < yLength)
+                        y = yNodes[yIndex];
+                    else break;
+                }
+                else
+                {
+                    sum += x._value * x._value;
+                    if (++xIndex < xLength)
+                        x = xNodes[xIndex];
+                    else break;
+                }
+            }
+
+            for (; xIndex < xLength; xIndex++)
+            {
+                double d = xNodes[xIndex]._value;
+                sum += d * d;
+            }
+
+            for (; yIndex < yLength; yIndex++)
+            {
+                double d = yNodes[yIndex]._value;
+                sum += d * d;
+            }
+
+            return sum;
+        }
+
+        public static double KernelFunction(Node[] x, Node[] y, Parameter param)
+        {
+            switch (param.KernelType)
+            {
+                case KernelType.LINEAR:
+                    return dot(x, y);
+                case KernelType.POLY:
+                    return powi(param.Degree * dot(x, y) + param.Coefficient0, param.Degree);
+                case KernelType.RBF:
+                    {
+                        double sum = computeSquaredDistance(x, y);
+                        return Math.Exp(-param.Gamma * sum);
+                    }
+                case KernelType.SIGMOID:
+                    return Math.Tanh(param.Gamma * dot(x, y) + param.Coefficient0);
+                case KernelType.PRECOMPUTED:
+                    return x[(int)(y[0].Value)].Value;
+                default:
+                    return 0;
+            }
+        }
+    }
+}
Index: /trunk/sources/LibSVM/LibSVM.csproj
===================================================================
--- /trunk/sources/LibSVM/LibSVM.csproj	(revision 2414)
+++ /trunk/sources/LibSVM/LibSVM.csproj	(revision 2415)
@@ -80,4 +80,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Kernel.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Cache.cs" />
@@ -95,5 +96,6 @@
     <Compile Include="Scaling.cs" />
     <Compile Include="Solver.cs" />
-    <Compile Include="SupportClass.cs" />
+    <Compile Include="SVMExtensions.cs" />
+    <Compile Include="TemporaryCulture.cs" />
     <Compile Include="Training.cs" />
   </ItemGroup>
Index: /trunk/sources/LibSVM/Model.cs
===================================================================
--- /trunk/sources/LibSVM/Model.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Model.cs	(revision 2415)
@@ -21,406 +21,470 @@
 using System;
 using System.IO;
-
-namespace SVM {
-  /// <remarks>
-  /// Encapsulates an SVM Model.
-  /// </remarks>
-  [Serializable]
-  public class Model {
-    private Parameter _parameter;
-    private int _numberOfClasses;
-    private int _supportVectorCount;
-    private Node[][] _supportVectors;
-    private double[][] _supportVectorCoefficients;
-    private double[] _rho;
-    private double[] _pairwiseProbabilityA;
-    private double[] _pairwiseProbabilityB;
-
-    private int[] _classLabels;
-    private int[] _numberOfSVPerClass;
-
-    internal Model() {
-    }
-
+using System.Threading;
+using System.Globalization;
+
+namespace SVM
+{
     /// <summary>
-    /// Parameter object.
+    /// Encapsulates an SVM Model.
     /// </summary>
-    public Parameter Parameter {
-      get {
-        return _parameter;
-      }
-      set {
-        _parameter = value;
-      }
-    }
-
-    /// <summary>
-    /// Number of classes in the model.
-    /// </summary>
-    public int NumberOfClasses {
-      get {
-        return _numberOfClasses;
-      }
-      set {
-        _numberOfClasses = value;
-      }
-    }
-
-    /// <summary>
-    /// Total number of support vectors.
-    /// </summary>
-    public int SupportVectorCount {
-      get {
-        return _supportVectorCount;
-      }
-      set {
-        _supportVectorCount = value;
-      }
-    }
-
-    /// <summary>
-    /// The support vectors.
-    /// </summary>
-    public Node[][] SupportVectors {
-      get {
-        return _supportVectors;
-      }
-      set {
-        _supportVectors = value;
-      }
-    }
-
-    /// <summary>
-    /// The coefficients for the support vectors.
-    /// </summary>
-    public double[][] SupportVectorCoefficients {
-      get {
-        return _supportVectorCoefficients;
-      }
-      set {
-        _supportVectorCoefficients = value;
-      }
-    }
-
-    /// <summary>
-    /// Rho values.
-    /// </summary>
-    public double[] Rho {
-      get {
-        return _rho;
-      }
-      set {
-        _rho = value;
-      }
-    }
-
-    /// <summary>
-    /// First pairwise probability.
-    /// </summary>
-    public double[] PairwiseProbabilityA {
-      get {
-        return _pairwiseProbabilityA;
-      }
-      set {
-        _pairwiseProbabilityA = value;
-      }
-    }
-
-    /// <summary>
-    /// Second pairwise probability.
-    /// </summary>
-    public double[] PairwiseProbabilityB {
-      get {
-        return _pairwiseProbabilityB;
-      }
-      set {
-        _pairwiseProbabilityB = value;
-      }
-    }
-
-    // for classification only
-
-    /// <summary>
-    /// Class labels.
-    /// </summary>
-    public int[] ClassLabels {
-      get {
-        return _classLabels;
-      }
-      set {
-        _classLabels = value;
-      }
-    }
-
-    /// <summary>
-    /// Number of support vectors per class.
-    /// </summary>
-    public int[] NumberOfSVPerClass {
-      get {
-        return _numberOfSVPerClass;
-      }
-      set {
-        _numberOfSVPerClass = value;
-      }
-    }
-
-    /// <summary>
-    /// Reads a Model from the provided file.
-    /// </summary>
-    /// <param name="filename">The name of the file containing the Model</param>
-    /// <returns>the Model</returns>
-    public static Model Read(string filename) {
-      FileStream input = File.OpenRead(filename);
-      try {
-        return Read(input);
-      }
-      finally {
-        input.Close();
-      }
-    }
-
-    /// <summary>
-    /// Reads a Model from the provided stream.
-    /// </summary>
-    /// <param name="stream">The stream from which to read the Model.</param>
-    /// <returns>the Model</returns>
-    public static Model Read(Stream stream) {
-      StreamReader input = new StreamReader(stream);
-
-      // read parameters
-
-      Model model = new Model();
-      Parameter param = new Parameter();
-      model.Parameter = param;
-      model.Rho = null;
-      model.PairwiseProbabilityA = null;
-      model.PairwiseProbabilityB = null;
-      model.ClassLabels = null;
-      model.NumberOfSVPerClass = null;
-
-      bool headerFinished = false;
-      while (!headerFinished) {
-        string line = input.ReadLine();
-        string cmd, arg;
-        int splitIndex = line.IndexOf(' ');
-        if (splitIndex >= 0) {
-          cmd = line.Substring(0, splitIndex);
-          arg = line.Substring(splitIndex + 1);
-        } else {
-          cmd = line;
-          arg = "";
-        }
-        arg = arg.ToLower();
-
-        int i, n;
-        switch (cmd) {
-          case "svm_type":
-            param.SvmType = (SvmType)Enum.Parse(typeof(SvmType), arg.ToUpper());
-            break;
-
-          case "kernel_type":
-            param.KernelType = (KernelType)Enum.Parse(typeof(KernelType), arg.ToUpper());
-            break;
-
-          case "degree":
-            param.Degree = int.Parse(arg);
-            break;
-
-          case "gamma":
-            param.Gamma = double.Parse(arg);
-            break;
-
-          case "coef0":
-            param.Coefficient0 = double.Parse(arg);
-            break;
-
-          case "nr_class":
-            model.NumberOfClasses = int.Parse(arg);
-            break;
-
-          case "total_sv":
-            model.SupportVectorCount = int.Parse(arg);
-            break;
-
-          case "rho":
-            n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
-            model.Rho = new double[n];
-            string[] rhoParts = arg.Split();
-            for (i = 0; i < n; i++)
-              model.Rho[i] = double.Parse(rhoParts[i]);
-            break;
-
-          case "label":
-            n = model.NumberOfClasses;
-            model.ClassLabels = new int[n];
-            string[] labelParts = arg.Split();
-            for (i = 0; i < n; i++)
-              model.ClassLabels[i] = int.Parse(labelParts[i]);
-            break;
-
-          case "probA":
-            n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
-            model.PairwiseProbabilityA = new double[n];
-            string[] probAParts = arg.Split();
-            for (i = 0; i < n; i++)
-              model.PairwiseProbabilityA[i] = double.Parse(probAParts[i]);
-            break;
-
-          case "probB":
-            n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
-            model.PairwiseProbabilityB = new double[n];
-            string[] probBParts = arg.Split();
-            for (i = 0; i < n; i++)
-              model.PairwiseProbabilityB[i] = double.Parse(probBParts[i]);
-            break;
-
-          case "nr_sv":
-            n = model.NumberOfClasses;
-            model.NumberOfSVPerClass = new int[n];
-            string[] nrsvParts = arg.Split();
-            for (i = 0; i < n; i++)
-              model.NumberOfSVPerClass[i] = int.Parse(nrsvParts[i]);
-            break;
-
-          case "SV":
-            headerFinished = true;
-            break;
-
-          default:
-            throw new Exception("Unknown text in model file");
-        }
-      }
-
-      // read sv_coef and SV
-
-      int m = model.NumberOfClasses - 1;
-      int l = model.SupportVectorCount;
-      model.SupportVectorCoefficients = new double[m][];
-      for (int i = 0; i < m; i++) {
-        model.SupportVectorCoefficients[i] = new double[l];
-      }
-      model.SupportVectors = new Node[l][];
-
-      for (int i = 0; i < l; i++) {
-        string[] parts = input.ReadLine().Trim().Split();
-
-        for (int k = 0; k < m; k++)
-          model.SupportVectorCoefficients[k][i] = double.Parse(parts[k]);
-        int n = parts.Length - m;
-        model.SupportVectors[i] = new Node[n];
-        for (int j = 0; j < n; j++) {
-          string[] nodeParts = parts[m + j].Split(':');
-          model.SupportVectors[i][j] = new Node();
-          model.SupportVectors[i][j].Index = int.Parse(nodeParts[0]);
-          model.SupportVectors[i][j].Value = double.Parse(nodeParts[1]);
-        }
-      }
-
-      return model;
-    }
-
-    /// <summary>
-    /// Writes a model to the provided filename.  This will overwrite any previous data in the file.
-    /// </summary>
-    /// <param name="filename">The desired file</param>
-    /// <param name="model">The Model to write</param>
-    public static void Write(string filename, Model model) {
-      FileStream stream = File.Open(filename, FileMode.Create);
-      try {
-        Write(stream, model);
-      }
-      finally {
-        stream.Close();
-      }
-    }
-
-    /// <summary>
-    /// Writes a model to the provided stream.
-    /// </summary>
-    /// <param name="stream">The output stream</param>
-    /// <param name="model">The model to write</param>
-    public static void Write(Stream stream, Model model) {
-      StreamWriter output = new StreamWriter(stream);
-
-      Parameter param = model.Parameter;
-
-      output.Write("svm_type " + param.SvmType + Environment.NewLine);
-      output.Write("kernel_type " + param.KernelType + Environment.NewLine);
-
-      if (param.KernelType == KernelType.POLY)
-        output.Write("degree " + param.Degree + Environment.NewLine);
-
-      if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.RBF || param.KernelType == KernelType.SIGMOID)
-        output.Write("gamma " + param.Gamma + Environment.NewLine);
-
-      if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.SIGMOID)
-        output.Write("coef0 " + param.Coefficient0 + Environment.NewLine);
-
-      int nr_class = model.NumberOfClasses;
-      int l = model.SupportVectorCount;
-      output.Write("nr_class " + nr_class + Environment.NewLine);
-      output.Write("total_sv " + l + Environment.NewLine);
-
-      {
-        output.Write("rho");
-        for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
-          output.Write(" " + model.Rho[i]);
-        output.Write(Environment.NewLine);
-      }
-
-      if (model.ClassLabels != null) {
-        output.Write("label");
-        for (int i = 0; i < nr_class; i++)
-          output.Write(" " + model.ClassLabels[i]);
-        output.Write(Environment.NewLine);
-      }
-
-      if (model.PairwiseProbabilityA != null)
-      // regression has probA only
-            {
-        output.Write("probA");
-        for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
-          output.Write(" " + model.PairwiseProbabilityA[i]);
-        output.Write(Environment.NewLine);
-      }
-      if (model.PairwiseProbabilityB != null) {
-        output.Write("probB");
-        for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
-          output.Write(" " + model.PairwiseProbabilityB[i]);
-        output.Write(Environment.NewLine);
-      }
-
-      if (model.NumberOfSVPerClass != null) {
-        output.Write("nr_sv");
-        for (int i = 0; i < nr_class; i++)
-          output.Write(" " + model.NumberOfSVPerClass[i]);
-        output.Write(Environment.NewLine);
-      }
-
-      output.Write("SV\n");
-      double[][] sv_coef = model.SupportVectorCoefficients;
-      Node[][] SV = model.SupportVectors;
-
-      for (int i = 0; i < l; i++) {
-        for (int j = 0; j < nr_class - 1; j++)
-          output.Write(sv_coef[j][i] + " ");
-
-        Node[] p = SV[i];
-        if (p.Length == 0) {
-          output.WriteLine();
-          continue;
-        }
-        if (param.KernelType == KernelType.PRECOMPUTED)
-          output.Write("0:{0}", (int)p[0].Value);
-        else {
-          output.Write("{0}:{1}", p[0].Index, p[0].Value);
-          for (int j = 1; j < p.Length; j++)
-            output.Write(" {0}:{1}", p[j].Index, p[j].Value);
-        }
-        output.WriteLine();
-      }
-
-      output.Flush();
-    }
-  }
+	[Serializable]
+	public class Model
+	{
+        private Parameter _parameter;
+        private int _numberOfClasses;
+        private int _supportVectorCount;
+        private Node[][] _supportVectors;
+        private double[][] _supportVectorCoefficients;
+        private double[] _rho;
+        private double[] _pairwiseProbabilityA;
+        private double[] _pairwiseProbabilityB;
+
+        private int[] _classLabels;
+        private int[] _numberOfSVPerClass;
+
+        internal Model()
+        {
+        }
+
+        /// <summary>
+        /// Parameter object.
+        /// </summary>
+        public Parameter Parameter
+        {
+            get
+            {
+                return _parameter;
+            }
+            set
+            {
+                _parameter = value;
+            }
+        }
+
+        /// <summary>
+        /// Number of classes in the model.
+        /// </summary>
+        public int NumberOfClasses
+        {
+            get
+            {
+                return _numberOfClasses;
+            }
+            set
+            {
+                _numberOfClasses = value;
+            }
+        }
+
+        /// <summary>
+        /// Total number of support vectors.
+        /// </summary>
+        public int SupportVectorCount
+        {
+            get
+            {
+                return _supportVectorCount;
+            }
+            set
+            {
+                _supportVectorCount = value;
+            }
+        }
+
+        /// <summary>
+        /// The support vectors.
+        /// </summary>
+        public Node[][] SupportVectors
+        {
+            get
+            {
+                return _supportVectors;
+            }
+            set
+            {
+                _supportVectors = value;
+            }
+        }
+
+        /// <summary>
+        /// The coefficients for the support vectors.
+        /// </summary>
+        public double[][] SupportVectorCoefficients
+        {
+            get
+            {
+                return _supportVectorCoefficients;
+            }
+            set
+            {
+                _supportVectorCoefficients = value;
+            }
+        }
+
+        /// <summary>
+        /// Rho values.
+        /// </summary>
+        public double[] Rho
+        {
+            get
+            {
+                return _rho;
+            }
+            set
+            {
+                _rho = value;
+            }
+        }
+
+        /// <summary>
+        /// First pairwise probability.
+        /// </summary>
+        public double[] PairwiseProbabilityA
+        {
+            get
+            {
+                return _pairwiseProbabilityA;
+            }
+            set
+            {
+                _pairwiseProbabilityA = value;
+            }
+        }
+
+        /// <summary>
+        /// Second pairwise probability.
+        /// </summary>
+        public double[] PairwiseProbabilityB
+        {
+            get
+            {
+                return _pairwiseProbabilityB;
+            }
+            set
+            {
+                _pairwiseProbabilityB = value;
+            }
+        }
+		
+		// for classification only
+
+        /// <summary>
+        /// Class labels.
+        /// </summary>
+        public int[] ClassLabels
+        {
+            get
+            {
+                return _classLabels;
+            }
+            set
+            {
+                _classLabels = value;
+            }
+        }
+
+        /// <summary>
+        /// Number of support vectors per class.
+        /// </summary>
+        public int[] NumberOfSVPerClass
+        {
+            get
+            {
+                return _numberOfSVPerClass;
+            }
+            set
+            {
+                _numberOfSVPerClass = value;
+            }
+        }
+
+        /// <summary>
+        /// Reads a Model from the provided file.
+        /// </summary>
+        /// <param name="filename">The name of the file containing the Model</param>
+        /// <returns>the Model</returns>
+        public static Model Read(string filename)
+        {
+            FileStream input = File.OpenRead(filename);
+            try
+            {
+                return Read(input);
+            }
+            finally
+            {
+                input.Close();
+            }
+        }
+
+        /// <summary>
+        /// Reads a Model from the provided stream.
+        /// </summary>
+        /// <param name="stream">The stream from which to read the Model.</param>
+        /// <returns>the Model</returns>
+        public static Model Read(Stream stream)
+        {
+            TemporaryCulture.Start();
+
+            StreamReader input = new StreamReader(stream);
+
+            // read parameters
+
+            Model model = new Model();
+            Parameter param = new Parameter();
+            model.Parameter = param;
+            model.Rho = null;
+            model.PairwiseProbabilityA = null;
+            model.PairwiseProbabilityB = null;
+            model.ClassLabels = null;
+            model.NumberOfSVPerClass = null;
+
+            bool headerFinished = false;
+            while (!headerFinished)
+            {
+                string line = input.ReadLine();
+                string cmd, arg;
+                int splitIndex = line.IndexOf(' ');
+                if (splitIndex >= 0)
+                {
+                    cmd = line.Substring(0, splitIndex);
+                    arg = line.Substring(splitIndex + 1);
+                }
+                else
+                {
+                    cmd = line;
+                    arg = "";
+                }
+                arg = arg.ToLower();
+
+                int i,n;
+                switch(cmd){
+                    case "svm_type":
+                        param.SvmType = (SvmType)Enum.Parse(typeof(SvmType), arg.ToUpper());
+                        break;
+                        
+                    case "kernel_type":
+                        param.KernelType = (KernelType)Enum.Parse(typeof(KernelType), arg.ToUpper());
+                        break;
+
+                    case "degree":
+                        param.Degree = int.Parse(arg);
+                        break;
+
+                    case "gamma":
+                        param.Gamma = double.Parse(arg);
+                        break;
+
+                    case "coef0":
+                        param.Coefficient0 = double.Parse(arg);
+                        break;
+
+                    case "nr_class":
+                        model.NumberOfClasses = int.Parse(arg);
+                        break;
+
+                    case "total_sv":
+                        model.SupportVectorCount = int.Parse(arg);
+                        break;
+
+                    case "rho":
+                        n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
+                        model.Rho = new double[n];
+                        string[] rhoParts = arg.Split();
+                        for(i=0; i<n; i++)
+                            model.Rho[i] = double.Parse(rhoParts[i]);
+                        break;
+
+                    case "label":
+                        n = model.NumberOfClasses;
+                        model.ClassLabels = new int[n];
+                        string[] labelParts = arg.Split();
+                        for (i = 0; i < n; i++)
+                            model.ClassLabels[i] = int.Parse(labelParts[i]);
+                        break;
+
+                    case "probA":
+                        n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
+                        model.PairwiseProbabilityA = new double[n];
+                            string[] probAParts = arg.Split();
+                        for (i = 0; i < n; i++)
+                            model.PairwiseProbabilityA[i] = double.Parse(probAParts[i]);
+                        break;
+
+                    case "probB":
+                        n = model.NumberOfClasses * (model.NumberOfClasses - 1) / 2;
+                        model.PairwiseProbabilityB = new double[n];
+                        string[] probBParts = arg.Split();
+                        for (i = 0; i < n; i++)
+                            model.PairwiseProbabilityB[i] = double.Parse(probBParts[i]);
+                        break;
+
+                    case "nr_sv":
+                        n = model.NumberOfClasses;
+                        model.NumberOfSVPerClass = new int[n];
+                        string[] nrsvParts = arg.Split();
+                        for (i = 0; i < n; i++)
+                            model.NumberOfSVPerClass[i] = int.Parse(nrsvParts[i]);
+                        break;
+
+                    case "SV":
+                        headerFinished = true;
+                        break;
+
+                    default:
+                        throw new Exception("Unknown text in model file");  
+                }
+            }
+
+            // read sv_coef and SV
+
+            int m = model.NumberOfClasses - 1;
+            int l = model.SupportVectorCount;
+            model.SupportVectorCoefficients = new double[m][];
+            for (int i = 0; i < m; i++)
+            {
+                model.SupportVectorCoefficients[i] = new double[l];
+            }
+            model.SupportVectors = new Node[l][];
+
+            for (int i = 0; i < l; i++)
+            {
+                string[] parts = input.ReadLine().Trim().Split();
+
+                for (int k = 0; k < m; k++)
+                    model.SupportVectorCoefficients[k][i] = double.Parse(parts[k]);
+                int n = parts.Length-m;
+                model.SupportVectors[i] = new Node[n];
+                for (int j = 0; j < n; j++)
+                {
+                    string[] nodeParts = parts[m + j].Split(':');
+                    model.SupportVectors[i][j] = new Node();
+                    model.SupportVectors[i][j].Index = int.Parse(nodeParts[0]);
+                    model.SupportVectors[i][j].Value = double.Parse(nodeParts[1]);
+                }
+            }
+
+            TemporaryCulture.Stop();
+
+            return model;
+        }
+
+        /// <summary>
+        /// Writes a model to the provided filename.  This will overwrite any previous data in the file.
+        /// </summary>
+        /// <param name="filename">The desired file</param>
+        /// <param name="model">The Model to write</param>
+        public static void Write(string filename, Model model)
+        {
+            FileStream stream = File.Open(filename, FileMode.Create);
+            try
+            {
+                Write(stream, model);
+            }
+            finally
+            {
+                stream.Close();
+            }
+        }
+
+        /// <summary>
+        /// Writes a model to the provided stream.
+        /// </summary>
+        /// <param name="stream">The output stream</param>
+        /// <param name="model">The model to write</param>
+        public static void Write(Stream stream, Model model)
+        {
+            TemporaryCulture.Start();
+
+            StreamWriter output = new StreamWriter(stream);
+
+            Parameter param = model.Parameter;
+
+            output.Write("svm_type " + param.SvmType + "\n");
+            output.Write("kernel_type " + param.KernelType + "\n");
+
+            if (param.KernelType == KernelType.POLY)
+                output.Write("degree " + param.Degree + "\n");
+
+            if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.RBF || param.KernelType == KernelType.SIGMOID)
+                output.Write("gamma " + param.Gamma + "\n");
+
+            if (param.KernelType == KernelType.POLY || param.KernelType == KernelType.SIGMOID)
+                output.Write("coef0 " + param.Coefficient0 + "\n");
+
+            int nr_class = model.NumberOfClasses;
+            int l = model.SupportVectorCount;
+            output.Write("nr_class " + nr_class + "\n");
+            output.Write("total_sv " + l + "\n");
+
+            {
+                output.Write("rho");
+                for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+                    output.Write(" " + model.Rho[i]);
+                output.Write("\n");
+            }
+
+            if (model.ClassLabels != null)
+            {
+                output.Write("label");
+                for (int i = 0; i < nr_class; i++)
+                    output.Write(" " + model.ClassLabels[i]);
+                output.Write("\n");
+            }
+
+            if (model.PairwiseProbabilityA != null)
+            // regression has probA only
+            {
+                output.Write("probA");
+                for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+                    output.Write(" " + model.PairwiseProbabilityA[i]);
+                output.Write("\n");
+            }
+            if (model.PairwiseProbabilityB != null)
+            {
+                output.Write("probB");
+                for (int i = 0; i < nr_class * (nr_class - 1) / 2; i++)
+                    output.Write(" " + model.PairwiseProbabilityB[i]);
+                output.Write("\n");
+            }
+
+            if (model.NumberOfSVPerClass != null)
+            {
+                output.Write("nr_sv");
+                for (int i = 0; i < nr_class; i++)
+                    output.Write(" " + model.NumberOfSVPerClass[i]);
+                output.Write("\n");
+            }
+
+            output.Write("SV\n");
+            double[][] sv_coef = model.SupportVectorCoefficients;
+            Node[][] SV = model.SupportVectors;
+
+            for (int i = 0; i < l; i++)
+            {
+                for (int j = 0; j < nr_class - 1; j++)
+                    output.Write(sv_coef[j][i] + " ");
+
+                Node[] p = SV[i];
+                if (p.Length == 0)
+                {
+                    output.WriteLine();
+                    continue;
+                }
+                if (param.KernelType == KernelType.PRECOMPUTED)
+                    output.Write("0:{0}", (int)p[0].Value);
+                else
+                {
+                    output.Write("{0}:{1}", p[0].Index, p[0].Value);
+                    for (int j = 1; j < p.Length; j++)
+                        output.Write(" {0}:{1}", p[j].Index, p[j].Value);
+                }
+                output.WriteLine();
+            }
+
+            output.Flush();
+
+            TemporaryCulture.Stop();
+        }
+	}
 }
Index: /trunk/sources/LibSVM/Node.cs
===================================================================
--- /trunk/sources/LibSVM/Node.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Node.cs	(revision 2415)
@@ -22,13 +22,13 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Encapsulates a node in a Problem vector, with an index and a value (for more efficient representation
     /// of sparse data.
-    /// </remarks>
+    /// </summary>
 	[Serializable]
 	public class Node : IComparable<Node>
 	{
-        private int _index;
-        private double _value;
+        internal int _index;
+        internal double _value;
 
         /// <summary>
Index: /trunk/sources/LibSVM/Parameter.cs
===================================================================
--- /trunk/sources/LibSVM/Parameter.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Parameter.cs	(revision 2415)
@@ -19,10 +19,12 @@
 
 using System;
+using System.Linq;
+using System.Collections.Generic;
 
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Contains all of the types of SVM this library can model.
-    /// </remarks>
+    /// </summary>
     public enum SvmType { 
         /// <summary>
@@ -47,7 +49,7 @@
         NU_SVR 
     };
-    /// <remarks>
+    /// <summary>
     /// Contains the various kernel types this library can use.
-    /// </remarks>
+    /// </summary>
     public enum KernelType { 
         /// <summary>
@@ -73,9 +75,9 @@
     };
 
-    /// <remarks>
+    /// <summary>
     /// This class contains the various parameters which can affect the way in which an SVM
     /// is learned.  Unless you know what you are doing, chances are you are best off using
     /// the default values.
-    /// </remarks>
+    /// </summary>
 	[Serializable]
 	public class Parameter : ICloneable
@@ -91,7 +93,5 @@
         private double _eps;
 
-        private int _weightCount;
-        private int[] _weightLabels;
-        private double[] _weights;
+        private Dictionary<int, double> _weights;
         private double _nu;
         private double _p;
@@ -116,7 +116,5 @@
             _shrinking = true;
             _probability = false;
-            _weightCount = 0;
-            _weightLabels = new int[0];
-            _weights = new double[0];
+            _weights = new Dictionary<int, double>();
         }
 
@@ -234,46 +232,15 @@
             }
         }
-        /// <summary>
-        /// Number of weights.
-        /// </summary>
-        public int WeightCount
-        {
-            get
-            {
-                return _weightCount;
-            }
-            set
-            {
-                _weightCount = value;
-            }
-        }
-        /// <summary>
-        /// Array of indicies corresponding to the Weights array (for C-SVC)
-        /// </summary>
-        public int[] WeightLabels
-        {
-            get
-            {
-                return _weightLabels;
-            }
-            set
-            {
-                _weightLabels = value;
-            }
-        }
-        /// <summary>
-        /// The parameter C of class i to weight*C in C-SVC (default 1)
-        /// </summary>
-        public double[] Weights
-        {
-            get
-            {
+
+        /// <summary>
+        /// Contains custom weights for class labels.  Default weight value is 1.
+        /// </summary>
+        public Dictionary<int,double> Weights
+        {
+            get{
                 return _weights;
             }
-            set
-            {
-                _weights = value;
-            }
-        }
+        }
+
         /// <summary>
         /// The parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
Index: /trunk/sources/LibSVM/ParameterSelection.cs
===================================================================
--- /trunk/sources/LibSVM/ParameterSelection.cs	(revision 2414)
+++ /trunk/sources/LibSVM/ParameterSelection.cs	(revision 2415)
@@ -24,8 +24,8 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// This class contains routines which perform parameter selection for a model which uses C-SVC and
     /// an RBF kernel.
-    /// </remarks>
+    /// </summary>
     public static class ParameterSelection
     {
@@ -142,5 +142,7 @@
             Gamma = 0;
             double crossValidation = double.MinValue;
-            StreamWriter output = new StreamWriter("graph.txt");
+            StreamWriter output = null;
+            if(outputFile != null)
+                output = new StreamWriter(outputFile);
             for(int i=0; i<CValues.Count; i++)
                 for (int j = 0; j < GammaValues.Count; j++)
@@ -150,5 +152,6 @@
                     double test = Training.PerformCrossValidation(problem, parameters, nrfold);
                     Console.Write("{0} {1} {2}", parameters.C, parameters.Gamma, test);
-                    output.WriteLine("{0} {1} {2}", parameters.C, parameters.Gamma, test);
+                    if(output != null)
+                        output.WriteLine("{0} {1} {2}", parameters.C, parameters.Gamma, test);
                     if (test > crossValidation)
                     {
@@ -160,5 +163,6 @@
                     else Console.WriteLine();
                 }
-            output.Close();
+            if(output != null)
+                output.Close();
         }
         /// <summary>
@@ -207,5 +211,7 @@
             Gamma = 0;
             double maxScore = double.MinValue;
-            StreamWriter output = new StreamWriter(outputFile);
+            StreamWriter output = null;
+            if(outputFile != null)
+                output = new StreamWriter(outputFile);
             for (int i = 0; i < CValues.Count; i++)
                 for (int j = 0; j < GammaValues.Count; j++)
@@ -216,5 +222,6 @@
                     double test = Prediction.Predict(validation, "tmp.txt", model, false);
                     Console.Write("{0} {1} {2}", parameters.C, parameters.Gamma, test);
-                    output.WriteLine("{0} {1} {2}", parameters.C, parameters.Gamma, test);
+                    if(output != null)
+                        output.WriteLine("{0} {1} {2}", parameters.C, parameters.Gamma, test);
                     if (test > maxScore)
                     {
@@ -226,5 +233,6 @@
                     else Console.WriteLine();
                 }
-            output.Close();
+            if(output != null)
+                output.Close();
         }
     }
Index: /trunk/sources/LibSVM/PerformanceEvaluator.cs
===================================================================
--- /trunk/sources/LibSVM/PerformanceEvaluator.cs	(revision 2414)
+++ /trunk/sources/LibSVM/PerformanceEvaluator.cs	(revision 2415)
@@ -21,10 +21,11 @@
 using System.Collections.Generic;
 using System.IO;
+using System.Globalization;
 
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Class encoding a member of a ranked set of labels.
-    /// </remarks>
+    /// </summary>
     public class RankPair : IComparable<RankPair>
     {
@@ -138,7 +139,7 @@
     }
 
-    /// <remarks>
+    /// <summary>
     /// Class which evaluates an SVM model using several standard techniques.
-    /// </remarks>
+    /// </summary>
     public class PerformanceEvaluator
     {
@@ -185,6 +186,6 @@
         /// <param name="model">Model to evaluate</param>
         /// <param name="problem">Problem to evaluate</param>
-        /// <param name="label">Label to be evaluate for</param>
-        public PerformanceEvaluator(Model model, Problem problem, double label) : this(model, problem, label, "tmp.results") { }
+        /// <param name="category">Label to be evaluate for</param>
+        public PerformanceEvaluator(Model model, Problem problem, double category) : this(model, problem, category, "tmp.results") { }
         /// <summary>
         /// Constructor.
@@ -220,5 +221,5 @@
             int confidenceIndex = -1;
             for (int i = 1; i < parts.Length; i++)
-                if (double.Parse(parts[i]) == category)
+                if (double.Parse(parts[i], CultureInfo.InvariantCulture) == category)
                 {
                     confidenceIndex = i;
@@ -229,6 +230,6 @@
             {
                 parts = input.ReadLine().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
-                double confidence = double.Parse(parts[confidenceIndex]);
-                _data.Add(new RankPair(confidence, labels[i]));
+                double confidence = double.Parse(parts[confidenceIndex], CultureInfo.InvariantCulture);
+                _data.Add(new RankPair(confidence, labels[i] == category ? 1 : 0));
             }
             input.Close();
Index: /trunk/sources/LibSVM/PrecomputedKernel.cs
===================================================================
--- /trunk/sources/LibSVM/PrecomputedKernel.cs	(revision 2414)
+++ /trunk/sources/LibSVM/PrecomputedKernel.cs	(revision 2415)
@@ -23,7 +23,7 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Class encapsulating a precomputed kernel, where each position indicates the similarity score for two items in the training data.
-    /// </remarks>
+    /// </summary>
     [Serializable]
     public class PrecomputedKernel
@@ -42,4 +42,40 @@
             _rows = _similarities.GetLength(0);
             _columns = _similarities.GetLength(1);
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="nodes">Nodes for self-similarity analysis</param>
+        /// <param name="param">Parameters to use when computing similarities</param>
+        public PrecomputedKernel(List<Node[]> nodes, Parameter param)
+        {
+            _rows = nodes.Count;
+            _columns = _rows;
+            _similarities = new float[_rows, _columns];
+            for (int r = 0; r < _rows; r++)
+            {
+                for (int c = 0; c < r; c++)
+                    _similarities[r, c] = _similarities[c, r];
+                _similarities[r, r] = 1;
+                for (int c = r + 1; c < _columns; c++)
+                    _similarities[r, c] = (float)Kernel.KernelFunction(nodes[r], nodes[c], param);
+            }
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="rows">Nodes to use as the rows of the matrix</param>
+        /// <param name="columns">Nodes to use as the columns of the matrix</param>
+        /// <param name="param">Parameters to use when compute similarities</param>
+        public PrecomputedKernel(List<Node[]> rows, List<Node[]> columns, Parameter param)
+        {
+            _rows = rows.Count;
+            _columns = columns.Count;
+            _similarities = new float[_rows, _columns];
+            for (int r = 0; r < _rows; r++)
+                for (int c = 0; c < _columns; c++)
+                    _similarities[r, c] = (float)Kernel.KernelFunction(rows[r], columns[c], param);
         }
 
Index: /trunk/sources/LibSVM/Prediction.cs
===================================================================
--- /trunk/sources/LibSVM/Prediction.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Prediction.cs	(revision 2415)
@@ -24,7 +24,7 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Class containing the routines to perform class membership prediction using a trained SVM.
-    /// </remarks>
+    /// </summary>
     public static class Prediction
     {
Index: /trunk/sources/LibSVM/Problem.cs
===================================================================
--- /trunk/sources/LibSVM/Problem.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Problem.cs	(revision 2415)
@@ -21,10 +21,12 @@
 using System.IO;
 using System.Collections.Generic;
+using System.Threading;
+using System.Globalization;
 
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Encapsulates a problem, or set of vectors which must be classified.
-    /// </remarks>
+    /// </summary>
 	[Serializable]
 	public class Problem
@@ -119,4 +121,6 @@
         public static Problem Read(Stream stream)
         {
+            TemporaryCulture.Start();
+
             StreamReader input = new StreamReader(stream);
             List<double> vy = new List<double>();
@@ -143,4 +147,6 @@
             }
 
+            TemporaryCulture.Stop();
+
             return new Problem(vy.Count, vy.ToArray(), vx.ToArray(), max_index);
         }
@@ -153,4 +159,6 @@
         public static void Write(Stream stream, Problem problem)
         {
+            TemporaryCulture.Start();
+
             StreamWriter output = new StreamWriter(stream);
             for (int i = 0; i < problem.Count; i++)
@@ -162,4 +170,6 @@
             }
             output.Flush();
+
+            TemporaryCulture.Stop();
         }
 
Index: /trunk/sources/LibSVM/Properties/AssemblyInfo.cs
===================================================================
--- /trunk/sources/LibSVM/Properties/AssemblyInfo.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Properties/AssemblyInfo.cs	(revision 2415)
@@ -6,10 +6,10 @@
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
-[assembly: AssemblyTitle("LibSVM")]
-[assembly: AssemblyDescription("")]
+[assembly: AssemblyTitle("SVM.NET")]
+[assembly: AssemblyDescription("A .NET Support Vector Machine library adapted from libsvm")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("Matthew Johnson")]
-[assembly: AssemblyProduct("SVM.NET Library")]
-[assembly: AssemblyCopyright("Copyright (C) 2008 Matthew Johnson")]
+[assembly: AssemblyProduct("SVM.NET")]
+[assembly: AssemblyCopyright("Copyright ©  Matthew Johnson 2009")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
@@ -21,5 +21,5 @@
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("1f115aaf-e714-4341-b2ad-5e84d30b6a1a")]
+[assembly: Guid("803d4e74-70db-432e-a4da-32e7a021eec2")]
 
 // Version information for an assembly consists of the following four values:
@@ -30,4 +30,6 @@
 //      Revision
 //
-[assembly: AssemblyVersion("2.84")]
-[assembly: AssemblyFileVersion("2.84")]
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.6.3")]
+[assembly: AssemblyFileVersion("1.6.3")]
Index: /trunk/sources/LibSVM/RangeTransform.cs
===================================================================
--- /trunk/sources/LibSVM/RangeTransform.cs	(revision 2414)
+++ /trunk/sources/LibSVM/RangeTransform.cs	(revision 2415)
@@ -20,12 +20,69 @@
 using System;
 using System.IO;
+using System.Threading;
+using System.Globalization;
 
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Class which encapsulates a range transformation.
-    /// </remarks>
+    /// </summary>
     public class RangeTransform : IRangeTransform
     {
+        /// <summary>
+        /// Default lower bound for scaling (-1).
+        /// </summary>
+        public const int DEFAULT_LOWER_BOUND = -1;
+        /// <summary>
+        /// Default upper bound for scaling (1).
+        /// </summary>
+        public const int DEFAULT_UPPER_BOUND = 1;
+
+        /// <summary>
+        /// Determines the Range transform for the provided problem.  Uses the default lower and upper bounds.
+        /// </summary>
+        /// <param name="prob">The Problem to analyze</param>
+        /// <returns>The Range transform for the problem</returns>
+        public static RangeTransform Compute(Problem prob)
+        {
+            return Compute(prob, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
+        }
+        /// <summary>
+        /// Determines the Range transform for the provided problem.
+        /// </summary>
+        /// <param name="prob">The Problem to analyze</param>
+        /// <param name="lowerBound">The lower bound for scaling</param>
+        /// <param name="upperBound">The upper bound for scaling</param>
+        /// <returns>The Range transform for the problem</returns>
+        public static RangeTransform Compute(Problem prob, double lowerBound, double upperBound)
+        {
+            double[] minVals = new double[prob.MaxIndex];
+            double[] maxVals = new double[prob.MaxIndex];
+            for (int i = 0; i < prob.MaxIndex; i++)
+            {
+                minVals[i] = double.MaxValue;
+                maxVals[i] = double.MinValue;
+            }
+            for (int i = 0; i < prob.Count; i++)
+            {
+                for (int j = 0; j < prob.X[i].Length; j++)
+                {
+                    int index = prob.X[i][j].Index - 1;
+                    double value = prob.X[i][j].Value;
+                    minVals[index] = Math.Min(minVals[index], value);
+                    maxVals[index] = Math.Max(maxVals[index], value);
+                }
+            }
+            for (int i = 0; i < prob.MaxIndex; i++)
+            {
+                if (minVals[i] == double.MaxValue || maxVals[i] == double.MinValue)
+                {
+                    minVals[i] = 0;
+                    maxVals[i] = 0;
+                }
+            }
+            return new RangeTransform(minVals, maxVals, lowerBound, upperBound);
+        }
+
         private double[] _inputStart;
         private double[] _inputScale;
@@ -72,5 +129,5 @@
         {
             Node[] output = new Node[input.Length];
-            for (int i = 0; i < _length; i++)
+            for (int i = 0; i < output.Length; i++)
             {
                 int index = input[i].Index;
@@ -104,4 +161,6 @@
         public static void Write(Stream stream, RangeTransform r)
         {
+            TemporaryCulture.Start();
+
             StreamWriter output = new StreamWriter(stream);
             output.WriteLine(r._length);
@@ -116,4 +175,6 @@
             output.WriteLine("{0} {1}", r._outputStart, r._outputScale);
             output.Flush();
+
+            TemporaryCulture.Stop();
         }
 
@@ -161,4 +222,6 @@
         public static RangeTransform Read(Stream stream)
         {
+            TemporaryCulture.Start();
+
             StreamReader input = new StreamReader(stream);
             int length = int.Parse(input.ReadLine());
@@ -174,4 +237,7 @@
             double outputStart = double.Parse(parts[0]);
             double outputScale = double.Parse(parts[1]);
+
+            TemporaryCulture.Stop();
+
             return new RangeTransform(inputStart, inputScale, outputStart, outputScale, length);
         }
Index: /trunk/sources/LibSVM/SVMExtensions.cs
===================================================================
--- /trunk/sources/LibSVM/SVMExtensions.cs	(revision 2415)
+++ /trunk/sources/LibSVM/SVMExtensions.cs	(revision 2415)
@@ -0,0 +1,17 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SVM
+{
+    internal static class SVMExtensions
+    {
+        public static void SwapIndex<T>(this T[] list, int i, int j)
+        {
+            T tmp = list[i];
+            list[i] = list[j];
+            list[j] = tmp;
+        }
+    }
+}
Index: /trunk/sources/LibSVM/Scaling.cs
===================================================================
--- /trunk/sources/LibSVM/Scaling.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Scaling.cs	(revision 2415)
@@ -22,64 +22,10 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Deals with the scaling of Problems so they have uniform ranges across all dimensions in order to
     /// result in better SVM performance.
-    /// </remarks>
+    /// </summary>
     public static class Scaling
     {
-        /// <summary>
-        /// Default lower bound for scaling (-1).
-        /// </summary>
-        public const int DEFAULT_LOWER_BOUND = -1;
-        /// <summary>
-        /// Default upper bound for scaling (1).
-        /// </summary>
-        public const int DEFAULT_UPPER_BOUND = 1;
-
-        /// <summary>
-        /// Determines the Range transform for the provided problem.  Uses the default lower and upper bounds.
-        /// </summary>
-        /// <param name="prob">The Problem to analyze</param>
-        /// <returns>The Range transform for the problem</returns>
-        public static RangeTransform DetermineRange(Problem prob)
-        {
-            return DetermineRangeTransform(prob, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
-        }
-        /// <summary>
-        /// Determines the Range transform for the provided problem.
-        /// </summary>
-        /// <param name="prob">The Problem to analyze</param>
-        /// <param name="lowerBound">The lower bound for scaling</param>
-        /// <param name="upperBound">The upper bound for scaling</param>
-        /// <returns>The Range transform for the problem</returns>
-        public static RangeTransform DetermineRangeTransform(Problem prob, double lowerBound, double upperBound)
-        {
-            double[] minVals = new double[prob.MaxIndex];
-            double[] maxVals = new double[prob.MaxIndex];
-            for (int i = 0; i < prob.MaxIndex; i++)
-            {
-                minVals[i] = double.MaxValue;
-                maxVals[i] = double.MinValue;
-            }
-            for (int i = 0; i < prob.Count; i++)
-            {
-                for (int j = 0; j < prob.X[i].Length; j++)
-                {
-                    int index = prob.X[i][j].Index-1;
-                    double value = prob.X[i][j].Value;
-                    minVals[index] = Math.Min(minVals[index], value);
-                    maxVals[index] = Math.Max(maxVals[index], value);
-                }
-            }
-            for (int i = 0; i < prob.MaxIndex; i++)
-            {
-                if (minVals[i] == double.MaxValue || maxVals[i] == double.MinValue)
-                {
-                    minVals[i] = 0;
-                    maxVals[i] = 0;
-                }
-            }
-            return new RangeTransform(minVals, maxVals, lowerBound, upperBound);
-        }
         /// <summary>
         /// Scales a problem using the provided range.  This will not affect the parameter.
@@ -88,5 +34,5 @@
         /// <param name="range">The Range transform to use in scaling</param>
         /// <returns>The Scaled problem</returns>
-        public static Problem Scale(Problem prob, IRangeTransform range)
+        public static Problem Scale(this IRangeTransform range, Problem prob)
         {
             Problem scaledProblem = new Problem(prob.Count, new double[prob.Count], new Node[prob.Count][], prob.MaxIndex);
Index: /trunk/sources/LibSVM/Solver.cs
===================================================================
--- /trunk/sources/LibSVM/Solver.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Solver.cs	(revision 2415)
@@ -19,179 +19,16 @@
 
 using System;
+using System.Linq;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.IO;
 
 namespace SVM
 {
-    //
-    // Kernel evaluation
-    //
-    // the static method k_function is for doing single kernel evaluation
-    // the constructor of Kernel prepares to calculate the l*l kernel matrix
-    // the member function get_Q is for getting one column from the Q Matrix
-    //
-    internal abstract class QMatrix
-    {
-        public abstract float[] get_Q(int column, int len);
-        public abstract float[] get_QD();
-        public abstract void swap_index(int i, int j);
-    }
-
-    internal abstract class Kernel : QMatrix
-    {
-        private Node[][] _x;
-        private double[] _x_square;
-
-        // Parameter
-        private KernelType kernel_type;
-        private int degree;
-        private double gamma;
-        private double coef0;
-
-        public override void swap_index(int i, int j)
-        {
-            do { Node[] _ = _x[i]; _x[i] = _x[j]; _x[j] = _; } while (false);
-            if (_x_square != null) do { double _ = _x_square[i]; _x_square[i] = _x_square[j]; _x_square[j] = _; } while (false);
-        }
-
-        private static double powi(double baseValue, int times)
-        {
-            double tmp = baseValue, ret = 1.0;
-
-            for (int t = times; t > 0; t /= 2)
-            {
-                if (t % 2 == 1) ret *= tmp;
-                tmp = tmp * tmp;
-            }
-            return ret;
-        }
-
-        private static double tanh(double x)
-        {
-            double e = Math.Exp(x);
-            return 1.0 - 2.0 / (e * e + 1);
-        }
-
-        public double kernel_function(int i, int j)
-        {
-            switch (kernel_type)
-            {
-                case KernelType.LINEAR:
-                    return dot(_x[i], _x[j]);
-                case KernelType.POLY:
-                    return powi(gamma * dot(_x[i], _x[j]) + coef0, degree);
-                case KernelType.RBF:
-                    return Math.Exp(-gamma * (_x_square[i] + _x_square[j] - 2 * dot(_x[i], _x[j])));
-                case KernelType.SIGMOID:
-                    return tanh(gamma * dot(_x[i], _x[j]) + coef0);
-                case KernelType.PRECOMPUTED:
-                    return _x[i][(int)(_x[j][0].Value)].Value;
-                default:
-                    return 0;
-            }
-        }
-
-        public Kernel(int l, Node[][] x_, Parameter param)
-        {
-            this.kernel_type = param.KernelType;
-            this.degree = param.Degree;
-            this.gamma = param.Gamma;
-            this.coef0 = param.Coefficient0;
-
-            _x = (Node[][])x_.Clone();
-
-            if (kernel_type == KernelType.RBF)
-            {
-                _x_square = new double[l];
-                for (int i = 0; i < l; i++)
-                    _x_square[i] = dot(_x[i], _x[i]);
-            }
-            else _x_square = null;
-        }
-
-        public static double dot(Node[] x, Node[] y)
-        {
-            double sum = 0;
-            int xlen = x.Length;
-            int ylen = y.Length;
-            int i = 0;
-            int j = 0;
-            while (i < xlen && j < ylen)
-            {
-                if (x[i].Index == y[j].Index)
-                    sum += x[i++].Value * y[j++].Value;
-                else
-                {
-                    if (x[i].Index > y[j].Index)
-                        ++j;
-                    else
-                        ++i;
-                }
-            }
-            return sum;
-        }
-
-        public static double k_function(Node[] x, Node[] y, Parameter param)
-        {
-            switch (param.KernelType)
-            {
-                case KernelType.LINEAR:
-                    return dot(x, y);
-                case KernelType.POLY:
-                    return powi(param.Gamma * dot(x, y) + param.Coefficient0, param.Degree);
-                case KernelType.RBF:
-                    {
-                        double sum = 0;
-                        int xlen = x.Length;
-                        int ylen = y.Length;
-                        int i = 0;
-                        int j = 0;
-                        while (i < xlen && j < ylen)
-                        {
-                            if (x[i].Index == y[j].Index)
-                            {
-                                double d = x[i++].Value - y[j++].Value;
-                                sum += d * d;
-                            }
-                            else if (x[i].Index > y[j].Index)
-                            {
-                                sum += y[j].Value * y[j].Value;
-                                ++j;
-                            }
-                            else
-                            {
-                                sum += x[i].Value * x[i].Value;
-                                ++i;
-                            }
-                        }
-
-                        while (i < xlen)
-                        {
-                            sum += x[i].Value * x[i].Value;
-                            ++i;
-                        }
-
-                        while (j < ylen)
-                        {
-                            sum += y[j].Value * y[j].Value;
-                            ++j;
-                        }
-
-                        return Math.Exp(-param.Gamma * sum);
-                    }
-                case KernelType.SIGMOID:
-                    return tanh(param.Gamma * dot(x, y) + param.Coefficient0);
-                case KernelType.PRECOMPUTED:
-                    return x[(int)(y[0].Value)].Value;
-                default:
-                    return 0;
-            }
-        }
-    }
 
     // An SMO algorithm in Fan et al., JMLR 6(2005), p. 1889--1918
     // Solves:
     //
-    //	min 0.5(\alpha^T Q \alpha) + p^T \alpha
+    //	Min 0.5(\alpha^T Q \alpha) + p^T \alpha
     //
     //		y^T \alpha = \delta
@@ -211,28 +48,29 @@
     {
         protected int active_size;
-        protected short[] y;
+        protected sbyte[] y;
         protected double[] G;		// gradient of objective function
-        protected const byte LOWER_BOUND = 0;
-        protected const byte UPPER_BOUND = 1;
-        protected const byte FREE = 2;
-        protected byte[] alpha_status;	// LOWER_BOUND, UPPER_BOUND, FREE
-        protected double[] alpha;
-        protected QMatrix Q;
+        private const byte LOWER_BOUND = 0;
+        private const byte UPPER_BOUND = 1;
+        private const byte FREE = 2;
+        private byte[] alpha_status;	// LOWER_BOUND, UPPER_BOUND, FREE
+        private double[] alpha;
+        protected IQMatrix Q;
         protected float[] QD;
-        protected double eps;
-        protected double Cp, Cn;
-        protected double[] p;
-        protected int[] active_set;
-        protected double[] G_bar;		// gradient, if we treat free variables as 0
+        protected double EPS;
+        private double Cp, Cn;
+        private double[] p;
+        private int[] active_set;
+        private double[] G_bar;		// gradient, if we treat free variables as 0
         protected int l;
-        protected bool unshrinked;	// XXX
+        protected bool unshrink;	// XXX
 
         protected const double INF = double.PositiveInfinity;
 
-        protected double get_C(int i)
+        private double get_C(int i)
         {
             return (y[i] > 0) ? Cp : Cn;
         }
-        protected void update_alpha_status(int i)
+
+        private void update_alpha_status(int i)
         {
             if (alpha[i] >= get_C(i))
@@ -242,11 +80,11 @@
             else alpha_status[i] = FREE;
         }
+
         protected bool is_upper_bound(int i) { return alpha_status[i] == UPPER_BOUND; }
         protected bool is_lower_bound(int i) { return alpha_status[i] == LOWER_BOUND; }
-        protected bool is_free(int i) { return alpha_status[i] == FREE; }
-
-        // java: information about solution except alpha,
-        // because we cannot return multiple values otherwise...
-        internal class SolutionInfo
+
+        private bool is_free(int i) { return alpha_status[i] == FREE; }
+
+        public class SolutionInfo
         {
             public double obj;
@@ -259,12 +97,12 @@
         protected void swap_index(int i, int j)
         {
-            Q.swap_index(i, j);
-            do { short _ = y[i]; y[i] = y[j]; y[j] = _; } while (false);
-            do { double _ = G[i]; G[i] = G[j]; G[j] = _; } while (false);
-            do { byte _ = alpha_status[i]; alpha_status[i] = alpha_status[j]; alpha_status[j] = _; } while (false);
-            do { double _ = alpha[i]; alpha[i] = alpha[j]; alpha[j] = _; } while (false);
-            do { double _ = p[i]; p[i] = p[j]; p[j] = _; } while (false);
-            do { int _ = active_set[i]; active_set[i] = active_set[j]; active_set[j] = _; } while (false);
-            do { double _ = G_bar[i]; G_bar[i] = G_bar[j]; G_bar[j] = _; } while (false);
+            Q.SwapIndex(i, j);
+            y.SwapIndex(i, j);
+            G.SwapIndex(i, j);
+            alpha_status.SwapIndex(i, j);
+            alpha.SwapIndex(i, j);
+            p.SwapIndex(i, j);
+            active_set.SwapIndex(i, j);
+            G_bar.SwapIndex(i, j);
         }
 
@@ -275,31 +113,52 @@
             if (active_size == l) return;
 
-            int i;
-            for (i = active_size; i < l; i++)
-                G[i] = G_bar[i] + p[i];
-
-            for (i = 0; i < active_size; i++)
-                if (is_free(i))
-                {
-                    float[] Q_i = Q.get_Q(i, l);
-                    double alpha_i = alpha[i];
-                    for (int j = active_size; j < l; j++)
-                        G[j] += alpha_i * Q_i[j];
-                }
-        }
-
-        public virtual void Solve(int l, QMatrix Q, double[] p_, short[] y_,
-               double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, bool shrinking)
+            int i, j;
+            int nr_free = 0;
+
+            for (j = active_size; j < l; j++)
+                G[j] = G_bar[j] + p[j];
+
+            for (j = 0; j < active_size; j++)
+                if (is_free(j))
+                    nr_free++;
+
+            if (2 * nr_free < active_size)
+                Procedures.info("\nWarning: using -h 0 may be faster\n");
+
+            if (nr_free * l > 2 * active_size * (l - active_size))
+            {
+                for (i = active_size; i < l; i++)
+                {
+                    float[] Q_i = Q.GetQ(i, active_size);
+                    for (j = 0; j < active_size; j++)
+                        if (is_free(j))
+                            G[i] += alpha[j] * Q_i[j];
+                }
+            }
+            else
+            {
+                for (i = 0; i < active_size; i++)
+                    if (is_free(i))
+                    {
+                        float[] Q_i = Q.GetQ(i, l);
+                        double alpha_i = alpha[i];
+                        for (j = active_size; j < l; j++)
+                            G[j] += alpha_i * Q_i[j];
+                    }
+            }
+        }
+
+        public virtual void Solve(int l, IQMatrix Q, double[] p_, sbyte[] y_, double[] alpha_, double Cp, double Cn, double eps, SolutionInfo si, bool shrinking)
         {
             this.l = l;
             this.Q = Q;
-            QD = Q.get_QD();
+            QD = Q.GetQD();
             p = (double[])p_.Clone();
-            y = (short[])y_.Clone();
+            y = (sbyte[])y_.Clone();
             alpha = (double[])alpha_.Clone();
             this.Cp = Cp;
             this.Cn = Cn;
-            this.eps = eps;
-            this.unshrinked = false;
+            this.EPS = eps;
+            this.unshrink = false;
 
             // initialize alpha_status
@@ -331,5 +190,5 @@
                     if (!is_lower_bound(i))
                     {
-                        float[] Q_i = Q.get_Q(i, l);
+                        float[] Q_i = Q.GetQ(i, l);
                         double alpha_i = alpha[i];
                         int j;
@@ -356,5 +215,5 @@
                     counter = Math.Min(l, 1000);
                     if (shrinking) do_shrinking();
-                    Debug.Write(".");
+                    Procedures.info(".");
                 }
 
@@ -365,5 +224,5 @@
                     // reset active set size and check
                     active_size = l;
-                    Debug.Write("*");
+                    Procedures.info("*");
                     if (select_working_set(working_set) != 0)
                         break;
@@ -379,6 +238,6 @@
                 // update alpha[i] and alpha[j], handle bounds carefully
 
-                float[] Q_i = Q.get_Q(i, active_size);
-                float[] Q_j = Q.get_Q(j, active_size);
+                float[] Q_i = Q.GetQ(i, active_size);
+                float[] Q_j = Q.GetQ(j, active_size);
 
                 double C_i = get_C(i);
@@ -495,5 +354,5 @@
                     if (ui != is_upper_bound(i))
                     {
-                        Q_i = Q.get_Q(i, l);
+                        Q_i = Q.GetQ(i, l);
                         if (ui)
                             for (k = 0; k < l; k++)
@@ -506,5 +365,5 @@
                     if (uj != is_upper_bound(j))
                     {
-                        Q_j = Q.get_Q(j, l);
+                        Q_j = Q.GetQ(j, l);
                         if (uj)
                             for (k = 0; k < l; k++)
@@ -541,21 +400,21 @@
             si.upper_bound_n = Cn;
 
-            Debug.Write("\noptimization finished, #iter = " + iter + "\n");
+            Procedures.info("\noptimization finished, #iter = " + iter + "\n");
         }
 
         // return 1 if already optimal, return 0 otherwise
-        protected virtual int select_working_set(int[] working_set)
+        int select_working_set(int[] working_set)
         {
             // return i,j such that
-            // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha)
+            // i: Maximizes -y_i * grad(f)_i, i in I_up(\alpha)
             // j: mimimizes the decrease of obj value
             //    (if quadratic coefficeint <= 0, replace it with tau)
             //    -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
 
-            double Gmax = -INF;
-            double Gmax2 = -INF;
-            int Gmax_idx = -1;
-            int Gmin_idx = -1;
-            double obj_diff_min = INF;
+            double GMax = -INF;
+            double GMax2 = -INF;
+            int GMax_idx = -1;
+            int GMin_idx = -1;
+            double obj_diff_Min = INF;
 
             for (int t = 0; t < active_size; t++)
@@ -563,8 +422,8 @@
                 {
                     if (!is_upper_bound(t))
-                        if (-G[t] >= Gmax)
-                        {
-                            Gmax = -G[t];
-                            Gmax_idx = t;
+                        if (-G[t] >= GMax)
+                        {
+                            GMax = -G[t];
+                            GMax_idx = t;
                         }
                 }
@@ -572,15 +431,15 @@
                 {
                     if (!is_lower_bound(t))
-                        if (G[t] >= Gmax)
-                        {
-                            Gmax = G[t];
-                            Gmax_idx = t;
-                        }
-                }
-
-            int i = Gmax_idx;
+                        if (G[t] >= GMax)
+                        {
+                            GMax = G[t];
+                            GMax_idx = t;
+                        }
+                }
+
+            int i = GMax_idx;
             float[] Q_i = null;
-            if (i != -1) // null Q_i not accessed: Gmax=-INF if i=-1
-                Q_i = Q.get_Q(i, active_size);
+            if (i != -1) // null Q_i not accessed: GMax=-INF if i=-1
+                Q_i = Q.GetQ(i, active_size);
 
             for (int j = 0; j < active_size; j++)
@@ -590,11 +449,11 @@
                     if (!is_lower_bound(j))
                     {
-                        double grad_diff = Gmax + G[j];
-                        if (G[j] >= Gmax2)
-                            Gmax2 = G[j];
+                        double grad_diff = GMax + G[j];
+                        if (G[j] >= GMax2)
+                            GMax2 = G[j];
                         if (grad_diff > 0)
                         {
                             double obj_diff;
-                            double quad_coef = Q_i[i] + QD[j] - 2 * y[i] * Q_i[j];
+                            double quad_coef = Q_i[i] + QD[j] - 2.0 * y[i] * Q_i[j];
                             if (quad_coef > 0)
                                 obj_diff = -(grad_diff * grad_diff) / quad_coef;
@@ -602,8 +461,8 @@
                                 obj_diff = -(grad_diff * grad_diff) / 1e-12;
 
-                            if (obj_diff <= obj_diff_min)
+                            if (obj_diff <= obj_diff_Min)
                             {
-                                Gmin_idx = j;
-                                obj_diff_min = obj_diff;
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
                             }
                         }
@@ -614,11 +473,11 @@
                     if (!is_upper_bound(j))
                     {
-                        double grad_diff = Gmax - G[j];
-                        if (-G[j] >= Gmax2)
-                            Gmax2 = -G[j];
+                        double grad_diff = GMax - G[j];
+                        if (-G[j] >= GMax2)
+                            GMax2 = -G[j];
                         if (grad_diff > 0)
                         {
                             double obj_diff;
-                            double quad_coef = Q_i[i] + QD[j] + 2 * y[i] * Q_i[j];
+                            double quad_coef = Q_i[i] + QD[j] + 2.0 * y[i] * Q_i[j];
                             if (quad_coef > 0)
                                 obj_diff = -(grad_diff * grad_diff) / quad_coef;
@@ -626,8 +485,8 @@
                                 obj_diff = -(grad_diff * grad_diff) / 1e-12;
 
-                            if (obj_diff <= obj_diff_min)
+                            if (obj_diff <= obj_diff_Min)
                             {
-                                Gmin_idx = j;
-                                obj_diff_min = obj_diff;
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
                             }
                         }
@@ -636,27 +495,27 @@
             }
 
-            if (Gmax + Gmax2 < eps)
+            if (GMax + GMax2 < EPS)
                 return 1;
 
-            working_set[0] = Gmax_idx;
-            working_set[1] = Gmin_idx;
+            working_set[0] = GMax_idx;
+            working_set[1] = GMin_idx;
             return 0;
         }
 
-        private bool be_shrunken(int i, double Gmax1, double Gmax2)
+        private bool be_shrunk(int i, double GMax1, double GMax2)
         {
             if (is_upper_bound(i))
             {
                 if (y[i] == +1)
-                    return (-G[i] > Gmax1);
+                    return (-G[i] > GMax1);
                 else
-                    return (-G[i] > Gmax2);
+                    return (-G[i] > GMax2);
             }
             else if (is_lower_bound(i))
             {
                 if (y[i] == +1)
-                    return (G[i] > Gmax2);
+                    return (G[i] > GMax2);
                 else
-                    return (G[i] > Gmax1);
+                    return (G[i] > GMax1);
             }
             else
@@ -664,11 +523,11 @@
         }
 
-        protected virtual void do_shrinking()
+        void do_shrinking()
         {
             int i;
-            double Gmax1 = -INF;		// max { -y_i * grad(f)_i | i in I_up(\alpha) }
-            double Gmax2 = -INF;		// max { y_i * grad(f)_i | i in I_low(\alpha) }
-
-            // find maximal violating pair first
+            double GMax1 = -INF;		// Max { -y_i * grad(f)_i | i in I_up(\alpha) }
+            double GMax2 = -INF;		// Max { y_i * grad(f)_i | i in I_low(\alpha) }
+
+            // find Maximal violating pair first
             for (i = 0; i < active_size; i++)
             {
@@ -677,11 +536,11 @@
                     if (!is_upper_bound(i))
                     {
-                        if (-G[i] >= Gmax1)
-                            Gmax1 = -G[i];
+                        if (-G[i] >= GMax1)
+                            GMax1 = -G[i];
                     }
                     if (!is_lower_bound(i))
                     {
-                        if (G[i] >= Gmax2)
-                            Gmax2 = G[i];
+                        if (G[i] >= GMax2)
+                            GMax2 = G[i];
                     }
                 }
@@ -690,24 +549,29 @@
                     if (!is_upper_bound(i))
                     {
-                        if (-G[i] >= Gmax2)
-                            Gmax2 = -G[i];
+                        if (-G[i] >= GMax2)
+                            GMax2 = -G[i];
                     }
                     if (!is_lower_bound(i))
                     {
-                        if (G[i] >= Gmax1)
-                            Gmax1 = G[i];
-                    }
-                }
-            }
-
-            // shrink
+                        if (G[i] >= GMax1)
+                            GMax1 = G[i];
+                    }
+                }
+            }
+
+            if (unshrink == false && GMax1 + GMax2 <= EPS * 10)
+            {
+                unshrink = true;
+                reconstruct_gradient();
+                active_size = l;
+            }
 
             for (i = 0; i < active_size; i++)
-                if (be_shrunken(i, Gmax1, Gmax2))
+                if (be_shrunk(i, GMax1, GMax2))
                 {
                     active_size--;
                     while (active_size > i)
                     {
-                        if (!be_shrunken(active_size, Gmax1, Gmax2))
+                        if (!be_shrunk(active_size, GMax1, GMax2))
                         {
                             swap_index(i, active_size);
@@ -717,29 +581,7 @@
                     }
                 }
-
-            // unshrink, check all variables again before sealed iterations
-
-            if (unshrinked || Gmax1 + Gmax2 > eps * 10) return;
-
-            unshrinked = true;
-            reconstruct_gradient();
-
-            for (i = l - 1; i >= active_size; i--)
-                if (!be_shrunken(i, Gmax1, Gmax2))
-                {
-                    while (active_size < i)
-                    {
-                        if (be_shrunken(active_size, Gmax1, Gmax2))
-                        {
-                            swap_index(i, active_size);
-                            break;
-                        }
-                        active_size++;
-                    }
-                    active_size++;
-                }
-        }
-
-        protected virtual double calculate_rho()
+        }
+
+        double calculate_rho()
         {
             double r;
@@ -786,9 +628,9 @@
     // additional constraint: e^T \alpha = constant
     //
-    sealed class Solver_NU : Solver
+    class Solver_NU : Solver
     {
         private SolutionInfo si;
 
-        public override void Solve(int l, QMatrix Q, double[] p, short[] y,
+        public sealed override void Solve(int l, IQMatrix Q, double[] p, sbyte[] y,
                double[] alpha, double Cp, double Cn, double eps,
                SolutionInfo si, bool shrinking)
@@ -799,22 +641,22 @@
 
         // return 1 if already optimal, return 0 otherwise
-        protected override int select_working_set(int[] working_set)
+        private int select_working_set(int[] working_set)
         {
             // return i,j such that y_i = y_j and
-            // i: maximizes -y_i * grad(f)_i, i in I_up(\alpha)
-            // j: minimizes the decrease of obj value
+            // i: Maximizes -y_i * grad(f)_i, i in I_up(\alpha)
+            // j: Minimizes the decrease of obj value
             //    (if quadratic coefficeint <= 0, replace it with tau)
             //    -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
 
-            double Gmaxp = -INF;
-            double Gmaxp2 = -INF;
-            int Gmaxp_idx = -1;
-
-            double Gmaxn = -INF;
-            double Gmaxn2 = -INF;
-            int Gmaxn_idx = -1;
-
-            int Gmin_idx = -1;
-            double obj_diff_min = INF;
+            double GMaxp = -INF;
+            double GMaxp2 = -INF;
+            int GMaxp_idx = -1;
+
+            double GMaxn = -INF;
+            double GMaxn2 = -INF;
+            int GMaxn_idx = -1;
+
+            int GMin_idx = -1;
+            double obj_diff_Min = INF;
 
             for (int t = 0; t < active_size; t++)
@@ -822,8 +664,8 @@
                 {
                     if (!is_upper_bound(t))
-                        if (-G[t] >= Gmaxp)
-                        {
-                            Gmaxp = -G[t];
-                            Gmaxp_idx = t;
+                        if (-G[t] >= GMaxp)
+                        {
+                            GMaxp = -G[t];
+                            GMaxp_idx = t;
                         }
                 }
@@ -831,19 +673,19 @@
                 {
                     if (!is_lower_bound(t))
-                        if (G[t] >= Gmaxn)
-                        {
-                            Gmaxn = G[t];
-                            Gmaxn_idx = t;
-                        }
-                }
-
-            int ip = Gmaxp_idx;
-            int iN = Gmaxn_idx;
+                        if (G[t] >= GMaxn)
+                        {
+                            GMaxn = G[t];
+                            GMaxn_idx = t;
+                        }
+                }
+
+            int ip = GMaxp_idx;
+            int iN = GMaxn_idx;
             float[] Q_ip = null;
             float[] Q_in = null;
-            if (ip != -1) // null Q_ip not accessed: Gmaxp=-INF if ip=-1
-                Q_ip = Q.get_Q(ip, active_size);
+            if (ip != -1) // null Q_ip not accessed: GMaxp=-INF if ip=-1
+                Q_ip = Q.GetQ(ip, active_size);
             if (iN != -1)
-                Q_in = Q.get_Q(iN, active_size);
+                Q_in = Q.GetQ(iN, active_size);
 
             for (int j = 0; j < active_size; j++)
@@ -853,7 +695,7 @@
                     if (!is_lower_bound(j))
                     {
-                        double grad_diff = Gmaxp + G[j];
-                        if (G[j] >= Gmaxp2)
-                            Gmaxp2 = G[j];
+                        double grad_diff = GMaxp + G[j];
+                        if (G[j] >= GMaxp2)
+                            GMaxp2 = G[j];
                         if (grad_diff > 0)
                         {
@@ -865,8 +707,8 @@
                                 obj_diff = -(grad_diff * grad_diff) / 1e-12;
 
-                            if (obj_diff <= obj_diff_min)
+                            if (obj_diff <= obj_diff_Min)
                             {
-                                Gmin_idx = j;
-                                obj_diff_min = obj_diff;
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
                             }
                         }
@@ -877,7 +719,7 @@
                     if (!is_upper_bound(j))
                     {
-                        double grad_diff = Gmaxn - G[j];
-                        if (-G[j] >= Gmaxn2)
-                            Gmaxn2 = -G[j];
+                        double grad_diff = GMaxn - G[j];
+                        if (-G[j] >= GMaxn2)
+                            GMaxn2 = -G[j];
                         if (grad_diff > 0)
                         {
@@ -889,8 +731,8 @@
                                 obj_diff = -(grad_diff * grad_diff) / 1e-12;
 
-                            if (obj_diff <= obj_diff_min)
+                            if (obj_diff <= obj_diff_Min)
                             {
-                                Gmin_idx = j;
-                                obj_diff_min = obj_diff;
+                                GMin_idx = j;
+                                obj_diff_Min = obj_diff;
                             }
                         }
@@ -899,31 +741,31 @@
             }
 
-            if (Math.Max(Gmaxp + Gmaxp2, Gmaxn + Gmaxn2) < eps)
+            if (Math.Max(GMaxp + GMaxp2, GMaxn + GMaxn2) < EPS)
                 return 1;
 
-            if (y[Gmin_idx] == +1)
-                working_set[0] = Gmaxp_idx;
+            if (y[GMin_idx] == +1)
+                working_set[0] = GMaxp_idx;
             else
-                working_set[0] = Gmaxn_idx;
-            working_set[1] = Gmin_idx;
+                working_set[0] = GMaxn_idx;
+            working_set[1] = GMin_idx;
 
             return 0;
         }
 
-        private bool be_shrunken(int i, double Gmax1, double Gmax2, double Gmax3, double Gmax4)
+        private bool be_shrunk(int i, double GMax1, double GMax2, double GMax3, double GMax4)
         {
             if (is_upper_bound(i))
             {
                 if (y[i] == +1)
-                    return (-G[i] > Gmax1);
+                    return (-G[i] > GMax1);
                 else
-                    return (-G[i] > Gmax4);
+                    return (-G[i] > GMax4);
             }
             else if (is_lower_bound(i))
             {
                 if (y[i] == +1)
-                    return (G[i] > Gmax2);
+                    return (G[i] > GMax2);
                 else
-                    return (G[i] > Gmax3);
+                    return (G[i] > GMax3);
             }
             else
@@ -931,12 +773,12 @@
         }
 
-        protected override void do_shrinking()
-        {
-            double Gmax1 = -INF;	// max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) }
-            double Gmax2 = -INF;	// max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) }
-            double Gmax3 = -INF;	// max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) }
-            double Gmax4 = -INF;	// max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) }
-
-            // find maximal violating pair first
+        private void do_shrinking()
+        {
+            double GMax1 = -INF;	// Max { -y_i * grad(f)_i | y_i = +1, i in I_up(\alpha) }
+            double GMax2 = -INF;	// Max { y_i * grad(f)_i | y_i = +1, i in I_low(\alpha) }
+            double GMax3 = -INF;	// Max { -y_i * grad(f)_i | y_i = -1, i in I_up(\alpha) }
+            double GMax4 = -INF;	// Max { y_i * grad(f)_i | y_i = -1, i in I_low(\alpha) }
+
+            // find Maximal violating pair first
             int i;
             for (i = 0; i < active_size; i++)
@@ -946,7 +788,7 @@
                     if (y[i] == +1)
                     {
-                        if (-G[i] > Gmax1) Gmax1 = -G[i];
-                    }
-                    else if (-G[i] > Gmax4) Gmax4 = -G[i];
+                        if (-G[i] > GMax1) GMax1 = -G[i];
+                    }
+                    else if (-G[i] > GMax4) GMax4 = -G[i];
                 }
                 if (!is_lower_bound(i))
@@ -954,19 +796,24 @@
                     if (y[i] == +1)
                     {
-                        if (G[i] > Gmax2) Gmax2 = G[i];
-                    }
-                    else if (G[i] > Gmax3) Gmax3 = G[i];
-                }
-            }
-
-            // shrinking
+                        if (G[i] > GMax2) GMax2 = G[i];
+                    }
+                    else if (G[i] > GMax3) GMax3 = G[i];
+                }
+            }
+
+            if (unshrink == false && Math.Max(GMax1 + GMax2, GMax3 + GMax4) <= EPS * 10)
+            {
+                unshrink = true;
+                reconstruct_gradient();
+                active_size = l;
+            }
 
             for (i = 0; i < active_size; i++)
-                if (be_shrunken(i, Gmax1, Gmax2, Gmax3, Gmax4))
+                if (be_shrunk(i, GMax1, GMax2, GMax3, GMax4))
                 {
                     active_size--;
                     while (active_size > i)
                     {
-                        if (!be_shrunken(active_size, Gmax1, Gmax2, Gmax3, Gmax4))
+                        if (!be_shrunk(active_size, GMax1, GMax2, GMax3, GMax4))
                         {
                             swap_index(i, active_size);
@@ -976,27 +823,7 @@
                     }
                 }
-
-            if (unshrinked || Math.Max(Gmax1 + Gmax2, Gmax3 + Gmax4) > eps * 10) return;
-
-            unshrinked = true;
-            reconstruct_gradient();
-
-            for (i = l - 1; i >= active_size; i--)
-                if (!be_shrunken(i, Gmax1, Gmax2, Gmax3, Gmax4))
-                {
-                    while (active_size < i)
-                    {
-                        if (be_shrunken(active_size, Gmax1, Gmax2, Gmax3, Gmax4))
-                        {
-                            swap_index(i, active_size);
-                            break;
-                        }
-                        active_size++;
-                    }
-                    active_size++;
-                }
-        }
-
-        protected override double calculate_rho()
+        }
+
+        private double calculate_rho()
         {
             int nr_free1 = 0, nr_free2 = 0;
@@ -1054,40 +881,40 @@
     class SVC_Q : Kernel
     {
-        private short[] y;
+        private sbyte[] y;
         private Cache cache;
         private float[] QD;
 
-        public SVC_Q(Problem prob, Parameter param, short[] y_) : base(prob.Count, prob.X, param)
-        {
-            y = (short[])y_.Clone();
+        public SVC_Q(Problem prob, Parameter param, sbyte[] y_) : base(prob.Count, prob.X, param)
+        {
+            y = (sbyte[])y_.Clone();
             cache = new Cache(prob.Count, (long)(param.CacheSize * (1 << 20)));
             QD = new float[prob.Count];
             for (int i = 0; i < prob.Count; i++)
-                QD[i] = (float)kernel_function(i, i);
-        }
-
-        public override float[] get_Q(int i, int len)
-        {
-            float[][] data = new float[1][];
-            int start;
-            if ((start = cache.get_data(i, data, len)) < len)
-            {
-                for (int j = start; j < len; j++)
-                    data[0][j] = (float)(y[i] * y[j] * kernel_function(i, j));
-            }
-            return data[0];
-        }
-
-        public override float[] get_QD()
+                QD[i] = (float)KernelFunction(i, i);
+        }
+
+        public override sealed float[] GetQ(int i, int len)
+        {
+            float[] data = null;
+            int start, j;
+            if ((start = cache.GetData(i, ref data, len)) < len)
+            {
+                for (j = start; j < len; j++)
+                    data[j] = (float)(y[i] * y[j] * KernelFunction(i, j));
+            }
+            return data;
+        }
+
+        public override sealed float[] GetQD()
         {
             return QD;
         }
 
-        public override void swap_index(int i, int j)
-        {
-            cache.swap_index(i, j);
-            base.swap_index(i, j);
-            do { short _ = y[i]; y[i] = y[j]; y[j] = _; } while (false);
-            do { float _ = QD[i]; QD[i] = QD[j]; QD[j] = _; } while (false);
+        public override sealed void SwapIndex(int i, int j)
+        {
+            cache.SwapIndex(i, j);
+            base.SwapIndex(i, j);
+            y.SwapIndex(i, j);
+            QD.SwapIndex(i, j);
         }
     }
@@ -1098,34 +925,34 @@
         private float[] QD;
 
-        public ONE_CLASS_Q(Problem prob, Parameter param) : base(prob.Count, prob.X, param)
+        public ONE_CLASS_Q(Problem prob, Parameter param) :  base(prob.Count, prob.X, param)
         {
             cache = new Cache(prob.Count, (long)(param.CacheSize * (1 << 20)));
             QD = new float[prob.Count];
             for (int i = 0; i < prob.Count; i++)
-                QD[i] = (float)kernel_function(i, i);
-        }
-
-        public override float[] get_Q(int i, int len)
-        {
-            float[][] data = new float[1][];
-            int start;
-            if ((start = cache.get_data(i, data, len)) < len)
-            {
-                for (int j = start; j < len; j++)
-                    data[0][j] = (float)kernel_function(i, j);
-            }
-            return data[0];
-        }
-
-        public override float[] get_QD()
+                QD[i] = (float)KernelFunction(i, i);
+        }
+
+        public override sealed float[] GetQ(int i, int len)
+        {
+            float[] data = null;
+            int start, j;
+            if ((start = cache.GetData(i, ref data, len)) < len)
+            {
+                for (j = start; j < len; j++)
+                    data[j] = (float)KernelFunction(i, j);
+            }
+            return data;
+        }
+
+        public override sealed float[] GetQD()
         {
             return QD;
         }
 
-        public override void swap_index(int i, int j)
-        {
-            cache.swap_index(i, j);
-            base.swap_index(i, j);
-            do { float _ = QD[i]; QD[i] = QD[j]; QD[j] = _; } while (false);
+        public override sealed void SwapIndex(int i, int j)
+        {
+            cache.SwapIndex(i, j);
+            base.SwapIndex(i, j);
+            QD.SwapIndex(i, j);
         }
     }
@@ -1135,5 +962,5 @@
         private int l;
         private Cache cache;
-        private short[] sign;
+        private sbyte[] sign;
         private int[] index;
         private int next_buffer;
@@ -1141,11 +968,10 @@
         private float[] QD;
 
-        public SVR_Q(Problem prob, Parameter param)
-            : base(prob.Count, prob.X, param)
+        public SVR_Q(Problem prob, Parameter param) : base(prob.Count, prob.X, param)
         {
             l = prob.Count;
             cache = new Cache(l, (long)(param.CacheSize * (1 << 20)));
             QD = new float[2 * l];
-            sign = new short[2 * l];
+            sign = new sbyte[2 * l];
             index = new int[2 * l];
             for (int k = 0; k < l; k++)
@@ -1155,5 +981,5 @@
                 index[k] = k;
                 index[k + l] = k;
-                QD[k] = (float)kernel_function(k, k);
+                QD[k] = (float)KernelFunction(k, k);
                 QD[k + l] = QD[k];
             }
@@ -1164,19 +990,19 @@
         }
 
-        public override void swap_index(int i, int j)
-        {
-            do { short _ = sign[i]; sign[i] = sign[j]; sign[j] = _; } while (false);
-            do { int _ = index[i]; index[i] = index[j]; index[j] = _; } while (false);
-            do { float _ = QD[i]; QD[i] = QD[j]; QD[j] = _; } while (false);
-        }
-
-        public override float[] get_Q(int i, int len)
-        {
-            float[][] data = new float[1][];
-            int real_i = index[i];
-            if (cache.get_data(real_i, data, l) < l)
-            {
-                for (int j = 0; j < l; j++)
-                    data[0][j] = (float)kernel_function(real_i, j);
+        public override sealed void SwapIndex(int i, int j)
+        {
+            sign.SwapIndex(i, j);
+            index.SwapIndex(i, j);
+            QD.SwapIndex(i, j);
+        }
+
+        public override sealed float[] GetQ(int i, int len)
+        {
+            float[] data = null;
+            int j, real_i = index[i];
+            if (cache.GetData(real_i, ref data, l) < l)
+            {
+                for (j = 0; j < l; j++)
+                    data[j] = (float)KernelFunction(real_i, j);
             }
 
@@ -1184,11 +1010,11 @@
             float[] buf = buffer[next_buffer];
             next_buffer = 1 - next_buffer;
-            short si = sign[i];
-            for (int j = 0; j < len; j++)
-                buf[j] = si * sign[j] * data[0][index[j]];
+            sbyte si = sign[i];
+            for (j = 0; j < len; j++)
+                buf[j] = (float)si * sign[j] * data[index[j]];
             return buf;
         }
 
-        public override float[] get_QD()
+        public override sealed float[] GetQD()
         {
             return QD;
@@ -1196,9 +1022,31 @@
     }
 
-    internal static class Procedures
+    internal class Procedures
     {
+        private static bool _verbose;
+        public static bool IsVerbose
+        {
+            get
+            {
+                return _verbose;
+            }
+            set
+            {
+                _verbose = value;
+            }
+        }
         //
         // construct and solve various formulations
         //
+        public const int LIBSVM_VERSION = 289;
+
+        public static TextWriter svm_print_string = Console.Out;
+
+        public static void info(string s)
+        {
+            if(_verbose)
+                svm_print_string.Write(s);
+        }
+
         private static void solve_c_svc(Problem prob, Parameter param,
                         double[] alpha, Solver.SolutionInfo si,
@@ -1206,6 +1054,6 @@
         {
             int l = prob.Count;
-            double[] minus_ones = new double[l];
-            short[] y = new short[l];
+            double[] Minus_ones = new double[l];
+            sbyte[] y = new sbyte[l];
 
             int i;
@@ -1214,10 +1062,10 @@
             {
                 alpha[i] = 0;
-                minus_ones[i] = -1;
+                Minus_ones[i] = -1;
                 if (prob.Y[i] > 0) y[i] = +1; else y[i] = -1;
             }
 
             Solver s = new Solver();
-            s.Solve(l, new SVC_Q(prob, param, y), minus_ones, y,
+            s.Solve(l, new SVC_Q(prob, param, y), Minus_ones, y,
                 alpha, Cp, Cn, param.EPS, si, param.Shrinking);
 
@@ -1227,5 +1075,5 @@
 
             if (Cp == Cn)
-                Debug.Write("nu = " + sum_alpha / (Cp * prob.Count) + "\n");
+                Procedures.info("nu = " + sum_alpha / (Cp * prob.Count) + "\n");
 
             for (i = 0; i < l; i++)
@@ -1240,5 +1088,5 @@
             double nu = param.Nu;
 
-            short[] y = new short[l];
+            sbyte[] y = new sbyte[l];
 
             for (i = 0; i < l; i++)
@@ -1269,9 +1117,8 @@
 
             Solver_NU s = new Solver_NU();
-            s.Solve(l, new SVC_Q(prob, param, y), zeros, y,
-                alpha, 1.0, 1.0, param.EPS, si, param.Shrinking);
+            s.Solve(l, new SVC_Q(prob, param, y), zeros, y, alpha, 1.0, 1.0, param.EPS, si, param.Shrinking);
             double r = si.r;
 
-            Debug.Write("C = " + 1 / r + "\n");
+            Procedures.info("C = " + 1 / r + "\n");
 
             for (i = 0; i < l; i++)
@@ -1285,9 +1132,9 @@
 
         private static void solve_one_class(Problem prob, Parameter param,
-                            double[] alpha, Solver.SolutionInfo si)
+                        double[] alpha, Solver.SolutionInfo si)
         {
             int l = prob.Count;
             double[] zeros = new double[l];
-            short[] ones = new short[l];
+            sbyte[] ones = new sbyte[l];
             int i;
 
@@ -1308,15 +1155,13 @@
 
             Solver s = new Solver();
-            s.Solve(l, new ONE_CLASS_Q(prob, param), zeros, ones,
-                alpha, 1.0, 1.0, param.EPS, si, param.Shrinking);
-        }
-
-        private static void solve_epsilon_svr(Problem prob, Parameter param,
-                        double[] alpha, Solver.SolutionInfo si)
+            s.Solve(l, new ONE_CLASS_Q(prob, param), zeros, ones, alpha, 1.0, 1.0, param.EPS, si, param.Shrinking);
+        }
+
+        private static void solve_epsilon_svr(Problem prob, Parameter param, double[] alpha, Solver.SolutionInfo si)
         {
             int l = prob.Count;
             double[] alpha2 = new double[2 * l];
             double[] linear_term = new double[2 * l];
-            short[] y = new short[2 * l];
+            sbyte[] y = new sbyte[2 * l];
             int i;
 
@@ -1333,6 +1178,5 @@
 
             Solver s = new Solver();
-            s.Solve(2 * l, new SVR_Q(prob, param), linear_term, y,
-                alpha2, param.C, param.C, param.EPS, si, param.Shrinking);
+            s.Solve(2 * l, new SVR_Q(prob, param), linear_term, y, alpha2, param.C, param.C, param.EPS, si, param.Shrinking);
 
             double sum_alpha = 0;
@@ -1342,5 +1186,5 @@
                 sum_alpha += Math.Abs(alpha[i]);
             }
-            Debug.Write("nu = " + sum_alpha / (param.C * l) + "\n");
+            Procedures.info("nu = " + sum_alpha / (param.C * l) + "\n");
         }
 
@@ -1352,5 +1196,5 @@
             double[] alpha2 = new double[2 * l];
             double[] linear_term = new double[2 * l];
-            short[] y = new short[2 * l];
+            sbyte[] y = new sbyte[2 * l];
             int i;
 
@@ -1371,5 +1215,5 @@
             s.Solve(2 * l, new SVR_Q(prob, param), linear_term, y, alpha2, C, C, param.EPS, si, param.Shrinking);
 
-            Debug.Write("epsilon = " + (-si.r) + "\n");
+            Procedures.info("epsilon = " + (-si.r) + "\n");
 
             for (i = 0; i < l; i++)
@@ -1380,5 +1224,5 @@
         // decision_function
         //
-        private class decision_function
+        internal class decision_function
         {
             public double[] alpha;
@@ -1386,7 +1230,5 @@
         };
 
-        static decision_function svm_train_one(
-            Problem prob, Parameter param,
-            double Cp, double Cn)
+        static decision_function svm_train_one(Problem prob, Parameter param, double Cp, double Cn)
         {
             double[] alpha = new double[prob.Count];
@@ -1411,5 +1253,5 @@
             }
 
-            Debug.Write("obj = " + si.obj + ", rho = " + si.rho + "\n");
+            Procedures.info("obj = " + si.obj + ", rho = " + si.rho + "\n");
 
             // output SVs
@@ -1435,5 +1277,5 @@
             }
 
-            Debug.Write("nSV = " + nSV + ", nBSV = " + nBSV + "\n");
+            Procedures.info("nSV = " + nSV + ", nBSV = " + nBSV + "\n");
 
             decision_function f = new decision_function();
@@ -1455,7 +1297,7 @@
                 else prior0 += 1;
 
-            int max_iter = 100; 	// Maximal number of iterations
-            double min_step = 1e-10;	// Minimal step taken in line search
-            double sigma = 1e-3;	// For numerically strict PD of Hessian
+            int Max_iter = 100;	// Maximal number of iterations
+            double Min_step = 1e-10;	// Minimal step taken in line search
+            double sigma = 1e-12;	// For numerically strict PD of Hessian
             double eps = 1e-5;
             double hiTarget = (prior1 + 1.0) / (prior1 + 2.0);
@@ -1480,5 +1322,5 @@
                     fval += (t[i] - 1) * fApB + Math.Log(1 + Math.Exp(fApB));
             }
-            for (iter = 0; iter < max_iter; iter++)
+            for (iter = 0; iter < Max_iter; iter++)
             {
                 // Update Gradient and Hessian (use H' = H + sigma I)
@@ -1519,6 +1361,6 @@
 
 
-                stepsize = 1; 		// Line Search
-                while (stepsize >= min_step)
+                stepsize = 1;		// Line Search
+                while (stepsize >= Min_step)
                 {
                     newA = A + stepsize * dA;
@@ -1545,13 +1387,13 @@
                 }
 
-                if (stepsize < min_step)
-                {
-                    Debug.Write("Line search fails in two-class probability estimates\n");
+                if (stepsize < Min_step)
+                {
+                    Procedures.info("Line search fails in two-class probability estimates\n");
                     break;
                 }
             }
 
-            if (iter >= max_iter)
-                Debug.Write("Reaching maximal iterations in two-class probability estimates\n");
+            if (iter >= Max_iter)
+                Procedures.info("Reaching Maximal iterations in two-class probability estimates\n");
             probAB[0] = A; probAB[1] = B;
         }
@@ -1568,66 +1410,65 @@
         // Method 2 from the multiclass_prob paper by Wu, Lin, and Weng
         private static void multiclass_probability(int k, double[,] r, double[] p)
-	{
-		int t,j;
-		int iter = 0, max_iter=Math.Max(100,k);
-		double[,] Q=new double[k,k];
-		double[] Qp= new double[k];
-		double pQp, eps=0.005/k;
-	
-		for (t=0;t<k;t++)
-		{
-			p[t]=1.0/k;  // Valid if k = 1
-			Q[t,t]=0;
-			for (j=0;j<t;j++)
-			{
-				Q[t,t]+=r[j,t]*r[j,t];
-				Q[t,j]=Q[j,t];
-			}
-			for (j=t+1;j<k;j++)
-			{
-				Q[t,t]+=r[j,t]*r[j,t];
-				Q[t,j]=-r[j,t]*r[t,j];
-			}
-		}
-		for (iter=0;iter<max_iter;iter++)
-		{
-			// stopping condition, recalculate QP,pQP for numerical accuracy
-			pQp=0;
-			for (t=0;t<k;t++)
-			{
-				Qp[t]=0;
-				for (j=0;j<k;j++)
-					Qp[t]+=Q[t,j]*p[j];
-				pQp+=p[t]*Qp[t];
-			}
-			double max_error=0;
-			for (t=0;t<k;t++)
-			{
-				double error=Math.Abs(Qp[t]-pQp);
-				if (error>max_error)
-					max_error=error;
-			}
-			if (max_error<eps) break;
-		
-			for (t=0;t<k;t++)
-			{
-				double diff=(-Qp[t]+pQp)/Q[t,t];
-				p[t]+=diff;
-				pQp=(pQp+diff*(diff*Q[t,t]+2*Qp[t]))/(1+diff)/(1+diff);
-				for (j=0;j<k;j++)
-				{
-					Qp[j]=(Qp[j]+diff*Q[t,j])/(1+diff);
-					p[j]/=(1+diff);
-				}
-			}
-		}
-		if (iter>=max_iter)
-			Debug.Write("Exceeds max_iter in multiclass_prob\n");
-	}
+        {
+            int t, j;
+            int iter = 0, Max_iter = Math.Max(100, k);
+            double[,] Q = new double[k,k];
+            double[] Qp = new double[k];
+            double pQp, eps = 0.005 / k;
+
+            for (t = 0; t < k; t++)
+            {
+                p[t] = 1.0 / k;  // Valid if k = 1
+                Q[t,t] = 0;
+                for (j = 0; j < t; j++)
+                {
+                    Q[t,t] += r[j,t] * r[j,t];
+                    Q[t,j] = Q[j,t];
+                }
+                for (j = t + 1; j < k; j++)
+                {
+                    Q[t,t] += r[j,t] * r[j,t];
+                    Q[t,j] = -r[j,t] * r[t,j];
+                }
+            }
+            for (iter = 0; iter < Max_iter; iter++)
+            {
+                // stopping condition, recalculate QP,pQP for numerical accuracy
+                pQp = 0;
+                for (t = 0; t < k; t++)
+                {
+                    Qp[t] = 0;
+                    for (j = 0; j < k; j++)
+                        Qp[t] += Q[t,j] * p[j];
+                    pQp += p[t] * Qp[t];
+                }
+                double Max_error = 0;
+                for (t = 0; t < k; t++)
+                {
+                    double error = Math.Abs(Qp[t] - pQp);
+                    if (error > Max_error)
+                        Max_error = error;
+                }
+                if (Max_error < eps) break;
+
+                for (t = 0; t < k; t++)
+                {
+                    double diff = (-Qp[t] + pQp) / Q[t,t];
+                    p[t] += diff;
+                    pQp = (pQp + diff * (diff * Q[t,t] + 2 * Qp[t])) / (1 + diff) / (1 + diff);
+                    for (j = 0; j < k; j++)
+                    {
+                        Qp[j] = (Qp[j] + diff * Q[t,j]) / (1 + diff);
+                        p[j] /= (1 + diff);
+                    }
+                }
+            }
+            if (iter >= Max_iter)
+                Procedures.info("Exceeds Max_iter in multiclass_prob\n");
+        }
 
         // Cross-validation decision values for probability estimates
         private static void svm_binary_svc_probability(Problem prob, Parameter param, double Cp, double Cn, double[] probAB)
         {
-            Random rand = new Random();
             int i;
             int nr_fold = 5;
@@ -1636,4 +1477,5 @@
 
             // random shuffle
+            Random rand = new Random();
             for (i = 0; i < prob.Count; i++) perm[i] = i;
             for (i = 0; i < prob.Count; i++)
@@ -1687,11 +1529,6 @@
                     subparam.Probability = false;
                     subparam.C = 1.0;
-                    subparam.WeightCount = 2;
-                    subparam.WeightLabels = new int[2];
-                    subparam.Weights = new double[2];
-                    subparam.WeightLabels[0] = +1;
-                    subparam.WeightLabels[1] = -1;
-                    subparam.Weights[0] = Cp;
-                    subparam.Weights[1] = Cn;
+                    subparam.Weights[1] = Cp;
+                    subparam.Weights[-1] = Cn;
                     Model submodel = svm_train(subprob, subparam);
                     for (j = begin; j < end; j++)
@@ -1718,5 +1555,5 @@
             Parameter newparam = (Parameter)param.Clone();
             newparam.Probability = false;
-            svm_cross_validation(prob, newparam, nr_fold, ymv, null);
+            svm_cross_validation(prob, newparam, nr_fold, ymv);
             for (i = 0; i < prob.Count; i++)
             {
@@ -1734,5 +1571,5 @@
                     mae += Math.Abs(ymv[i]);
             mae /= (prob.Count - count);
-            Debug.Write("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + mae + "\n");
+            Procedures.info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + mae + "\n");
             return mae;
         }
@@ -1743,8 +1580,8 @@
         {
             int l = prob.Count;
-            int max_nr_class = 16;
+            int Max_nr_class = 16;
             int nr_class = 0;
-            int[] label = new int[max_nr_class];
-            int[] count = new int[max_nr_class];
+            int[] label = new int[Max_nr_class];
+            int[] count = new int[Max_nr_class];
             int[] data_label = new int[l];
             int i;
@@ -1765,11 +1602,11 @@
                 if (j == nr_class)
                 {
-                    if (nr_class == max_nr_class)
-                    {
-                        max_nr_class *= 2;
-                        int[] new_data = new int[max_nr_class];
+                    if (nr_class == Max_nr_class)
+                    {
+                        Max_nr_class *= 2;
+                        int[] new_data = new int[Max_nr_class];
                         Array.Copy(label, 0, new_data, 0, label.Length);
                         label = new_data;
-                        new_data = new int[max_nr_class];
+                        new_data = new int[Max_nr_class];
                         Array.Copy(count, 0, new_data, 0, count.Length);
                         count = new_data;
@@ -1808,15 +1645,15 @@
             model.Parameter = param;
 
-            if (param.SvmType == SvmType.ONE_CLASS ||
+            if (param.SvmType == SvmType.ONE_CLASS || 
                param.SvmType == SvmType.EPSILON_SVR ||
                param.SvmType == SvmType.NU_SVR)
             {
                 // regression or one-class-svm
-                model.NumberOfClasses = 2;
+                model.NumberOfClasses = 2;                
                 model.ClassLabels = null;
                 model.NumberOfSVPerClass = null;
                 model.PairwiseProbabilityA = null; model.PairwiseProbabilityB = null;
                 model.SupportVectorCoefficients = new double[1][];
-
+                
                 if (param.Probability &&
                    (param.SvmType == SvmType.EPSILON_SVR ||
@@ -1834,5 +1671,5 @@
                 int i;
                 for (i = 0; i < prob.Count; i++)
-                    if (Math.Abs(f.alpha[i]) > 0) ++nSV;
+                    if (Math.Abs(f.alpha[i]) > 0) ++nSV;                
                 model.SupportVectorCount = nSV;
                 model.SupportVectors = new Node[nSV][];
@@ -1873,14 +1710,10 @@
                 for (i = 0; i < nr_class; i++)
                     weighted_C[i] = param.C;
-                for (i = 0; i < param.WeightCount; i++)
-                {
-                    int j;
-                    for (j = 0; j < nr_class; j++)
-                        if (param.WeightLabels[i] == label[j])
-                            break;
-                    if (j == nr_class)
-                        Debug.Write("warning: class label " + param.WeightLabels[i] + " specified in weight is not found\n");
-                    else
-                        weighted_C[j] *= param.Weights[i];
+                foreach (int weightedLabel in param.Weights.Keys)
+                {
+                    int index = Array.IndexOf<int>(label, weightedLabel);
+                    if (index < 0)
+                        Console.Error.WriteLine("warning: class label " + weightedLabel + " specified in weight is not found");
+                    else weighted_C[index] *= param.Weights[weightedLabel];
                 }
 
@@ -1983,5 +1816,5 @@
                 }
 
-                Debug.Write("Total nSV = " + nnz + "\n");
+                Procedures.info("Total nSV = " + nnz + "\n");
 
                 model.SupportVectorCount = nnz;
@@ -2029,5 +1862,5 @@
 
         // Stratified cross validation
-        public static void svm_cross_validation(Problem prob, Parameter param, int nr_fold, double[] target, Dictionary<int,double>[] confidence)
+        public static void svm_cross_validation(Problem prob, Parameter param, int nr_fold, double[] target)
         {
             Random rand = new Random();
@@ -2131,13 +1964,7 @@
                     param.SvmType == SvmType.NU_SVC))
                 {
+                    double[] prob_estimates = new double[svm_get_nr_class(submodel)];
                     for (j = begin; j < end; j++)
-                    {
-                        double[] prob_estimates = new double[svm_get_nr_class(submodel)];
                         target[perm[j]] = svm_predict_probability(submodel, prob.X[perm[j]], prob_estimates);
-                        confidence[perm[j]] = new Dictionary<int, double>();
-                        for (int label = 0; label < prob_estimates.Length; label++)
-                            confidence[perm[j]][submodel.ClassLabels[label]] = prob_estimates[label];
-
-                    }
                 }
                 else
@@ -2171,5 +1998,5 @@
             else
             {
-                Debug.Write("Model doesn't contain information for SVR probability inference\n");
+                Console.Error.WriteLine("Model doesn't contain information for SVR probability inference");
                 return 0;
             }
@@ -2185,5 +2012,5 @@
                 double sum = 0;
                 for (int i = 0; i < model.SupportVectorCount; i++)
-                    sum += sv_coef[i] * Kernel.k_function(x, model.SupportVectors[i], model.Parameter);
+                    sum += sv_coef[i] * Kernel.KernelFunction(x, model.SupportVectors[i], model.Parameter);
                 sum -= model.Rho[0];
                 dec_values[0] = sum;
@@ -2197,5 +2024,5 @@
                 double[] kvalue = new double[l];
                 for (i = 0; i < l; i++)
-                    kvalue[i] = Kernel.k_function(x, model.SupportVectors[i], model.Parameter);
+                    kvalue[i] = Kernel.KernelFunction(x, model.SupportVectors[i], model.Parameter);
 
                 int[] start = new int[nr_class];
@@ -2262,53 +2089,45 @@
                     }
 
-                int vote_max_idx = 0;
+                int vote_Max_idx = 0;
                 for (i = 1; i < nr_class; i++)
-                    if (vote[i] > vote[vote_max_idx])
-                        vote_max_idx = i;
-                return model.ClassLabels[vote_max_idx];
+                    if (vote[i] > vote[vote_Max_idx])
+                        vote_Max_idx = i;
+                return model.ClassLabels[vote_Max_idx];
             }
         }
 
         public static double svm_predict_probability(Model model, Node[] x, double[] prob_estimates)
-	{
-        if ((model.Parameter.SvmType == SvmType.C_SVC || model.Parameter.SvmType == SvmType.NU_SVC) &&
-		    model.PairwiseProbabilityA!=null && model.PairwiseProbabilityB!=null)
-		{
-			int i;
-			int nr_class = model.NumberOfClasses;
-			double[] dec_values = new double[nr_class*(nr_class-1)/2];
-			svm_predict_values(model, x, dec_values);
-
-			double min_prob=1e-7;
-			double[,] pairwise_prob=new double[nr_class,nr_class];
-			
-			int k=0;
-			for(i=0;i<nr_class;i++)
-				for(int j=i+1;j<nr_class;j++)
-				{
-					pairwise_prob[i,j]=Math.Min(Math.Max(sigmoid_predict(dec_values[k],model.PairwiseProbabilityA[k],model.PairwiseProbabilityB[k]),min_prob),1-min_prob);
-					pairwise_prob[j,i]=1-pairwise_prob[i,j];
-					k++;
-				}
-			multiclass_probability(nr_class,pairwise_prob,prob_estimates);
-
-			int prob_max_idx = 0;
-			for(i=1;i<nr_class;i++)
-				if(prob_estimates[i] > prob_estimates[prob_max_idx])
-					prob_max_idx = i;
-			return model.ClassLabels[prob_max_idx];
-		}
-		else 
-			return svm_predict(model, x);
-	}
-
-        private static double atof(string s)
-        {
-            return double.Parse(s);
-        }
-
-        private static int atoi(string s)
-        {
-            return int.Parse(s);
+        {
+            if ((model.Parameter.SvmType == SvmType.C_SVC || model.Parameter.SvmType == SvmType.NU_SVC) &&
+                model.PairwiseProbabilityA != null && model.PairwiseProbabilityB != null)
+            {
+                int i;
+                int nr_class = model.NumberOfClasses;
+                double[] dec_values = new double[nr_class * (nr_class - 1) / 2];
+                svm_predict_values(model, x, dec_values);
+
+                double Min_prob = 1e-7;
+                double[,] pairwise_prob = new double[nr_class, nr_class];
+
+                int k = 0;
+                for (i = 0; i < nr_class; i++)
+                {
+                    for (int j = i + 1; j < nr_class; j++)
+                    {
+                        pairwise_prob[i, j] = Math.Min(Math.Max(sigmoid_predict(dec_values[k], model.PairwiseProbabilityA[k], model.PairwiseProbabilityB[k]), Min_prob), 1 - Min_prob);
+                        pairwise_prob[j, i] = 1 - pairwise_prob[i, j];
+                        k++;
+                    }
+                }
+                multiclass_probability(nr_class, pairwise_prob, prob_estimates);
+
+                int prob_Max_idx = 0;
+                for (i = 1; i < nr_class; i++)
+                    if (prob_estimates[i] > prob_estimates[prob_Max_idx])
+                        prob_Max_idx = i;
+                return model.ClassLabels[prob_Max_idx];
+            }
+            else
+                return svm_predict(model, x);
         }
 
@@ -2318,20 +2137,8 @@
 
             SvmType svm_type = param.SvmType;
-            if (svm_type != SvmType.C_SVC &&
-               svm_type != SvmType.NU_SVC &&
-               svm_type != SvmType.ONE_CLASS &&
-               svm_type != SvmType.EPSILON_SVR &&
-               svm_type != SvmType.NU_SVR)
-                return "unknown svm type";
 
             // kernel_type, degree
 
             KernelType kernel_type = param.KernelType;
-            if (kernel_type != KernelType.LINEAR &&
-               kernel_type != KernelType.POLY &&
-               kernel_type != KernelType.RBF &&
-               kernel_type != KernelType.SIGMOID &&
-               kernel_type != KernelType.PRECOMPUTED)
-                return "unknown kernel type";
 
             if (param.Degree < 0)
@@ -2345,4 +2152,7 @@
             if (param.EPS <= 0)
                 return "eps <= 0";
+
+            if (param.Gamma == 0)
+                param.Gamma = 1.0 / prob.MaxIndex;
 
             if (svm_type == SvmType.C_SVC ||
@@ -2362,5 +2172,6 @@
                     return "p < 0";
 
-            if (param.Probability && svm_type == SvmType.ONE_CLASS)
+            if (param.Probability &&
+               svm_type == SvmType.ONE_CLASS)
                 return "one-class SVM probability output not supported yet";
 
@@ -2370,8 +2181,8 @@
             {
                 int l = prob.Count;
-                int max_nr_class = 16;
+                int Max_nr_class = 16;
                 int nr_class = 0;
-                int[] label = new int[max_nr_class];
-                int[] count = new int[max_nr_class];
+                int[] label = new int[Max_nr_class];
+                int[] count = new int[Max_nr_class];
 
                 int i;
@@ -2389,12 +2200,12 @@
                     if (j == nr_class)
                     {
-                        if (nr_class == max_nr_class)
-                        {
-                            max_nr_class *= 2;
-                            int[] new_data = new int[max_nr_class];
+                        if (nr_class == Max_nr_class)
+                        {
+                            Max_nr_class *= 2;
+                            int[] new_data = new int[Max_nr_class];
                             Array.Copy(label, 0, new_data, 0, label.Length);
                             label = new_data;
 
-                            new_data = new int[max_nr_class];
+                            new_data = new int[Max_nr_class];
                             Array.Copy(count, 0, new_data, 0, count.Length);
                             count = new_data;
@@ -2432,4 +2243,3 @@
         }
     }
-
 }
Index: unk/sources/LibSVM/SupportClass.cs
===================================================================
--- /trunk/sources/LibSVM/SupportClass.cs	(revision 2414)
+++ 	(revision )
@@ -1,213 +1,0 @@
-//
-// In order to convert some functionality to Visual C#, the Java Language Conversion Assistant
-// creates "support classes" that duplicate the original functionality.  
-//
-// Support classes replicate the functionality of the original code, but in some cases they are 
-// substantially different architecturally. Although every effort is made to preserve the 
-// original architecture of the application in the converted project, the user should be aware that 
-// the primary goal of these support classes is to replicate functionality, and that at times 
-// the architecture of the resulting solution may differ somewhat.
-//
-
-using System;
-
-/// <summary>
-/// Contains conversion support elements such as classes, interfaces and static methods.
-/// </summary>
-public class SupportClass
-{
-	//Provides access to a static System.Random class instance
-	static public System.Random Random = new System.Random();
-
-	/*******************************/
-	/// <summary>
-	/// The class performs token processing in strings
-	/// </summary>
-	public class Tokenizer: System.Collections.IEnumerator
-	{
-		/// Position over the string
-		private long currentPos = 0;
-
-		/// Include demiliters in the results.
-		private bool includeDelims = false;
-
-		/// Char representation of the String to tokenize.
-		private char[] chars = null;
-			
-		//The tokenizer uses the default delimiter set: the space character, the tab character, the newline character, and the carriage-return character and the form-feed character
-		private string delimiters = " \t\n\r\f";		
-
-		/// <summary>
-		/// Initializes a new class instance with a specified string to process
-		/// </summary>
-		/// <param name="source">String to tokenize</param>
-		public Tokenizer(System.String source)
-		{			
-			this.chars = source.ToCharArray();
-		}
-
-		/// <summary>
-		/// Initializes a new class instance with a specified string to process
-		/// and the specified token delimiters to use
-		/// </summary>
-		/// <param name="source">String to tokenize</param>
-		/// <param name="delimiters">String containing the delimiters</param>
-		public Tokenizer(System.String source, System.String delimiters):this(source)
-		{			
-			this.delimiters = delimiters;
-		}
-
-
-		/// <summary>
-		/// Initializes a new class instance with a specified string to process, the specified token 
-		/// delimiters to use, and whether the delimiters must be included in the results.
-		/// </summary>
-		/// <param name="source">String to tokenize</param>
-		/// <param name="delimiters">String containing the delimiters</param>
-		/// <param name="includeDelims">Determines if delimiters are included in the results.</param>
-		public Tokenizer(System.String source, System.String delimiters, bool includeDelims):this(source,delimiters)
-		{
-			this.includeDelims = includeDelims;
-		}	
-
-
-		/// <summary>
-		/// Returns the next token from the token list
-		/// </summary>
-		/// <returns>The string value of the token</returns>
-		public System.String NextToken()
-		{				
-			return NextToken(this.delimiters);
-		}
-
-		/// <summary>
-		/// Returns the next token from the source string, using the provided
-		/// token delimiters
-		/// </summary>
-		/// <param name="delimiters">String containing the delimiters to use</param>
-		/// <returns>The string value of the token</returns>
-		public System.String NextToken(System.String delimiters)
-		{
-			//According to documentation, the usage of the received delimiters should be temporary (only for this call).
-			//However, it seems it is not true, so the following line is necessary.
-			this.delimiters = delimiters;
-
-			//at the end 
-			if (this.currentPos == this.chars.Length)
-				throw new System.ArgumentOutOfRangeException();
-			//if over a delimiter and delimiters must be returned
-			else if (   (System.Array.IndexOf(delimiters.ToCharArray(),chars[this.currentPos]) != -1)
-				     && this.includeDelims )                	
-				return "" + this.chars[this.currentPos++];
-			//need to get the token wo delimiters.
-			else
-				return nextToken(delimiters.ToCharArray());
-		}
-
-		//Returns the nextToken wo delimiters
-		private System.String nextToken(char[] delimiters)
-		{
-			string token="";
-			long pos = this.currentPos;
-
-			//skip possible delimiters
-			while (System.Array.IndexOf(delimiters,this.chars[currentPos]) != -1)
-				//The last one is a delimiter (i.e there is no more tokens)
-				if (++this.currentPos == this.chars.Length)
-				{
-					this.currentPos = pos;
-					throw new System.ArgumentOutOfRangeException();
-				}
-			
-			//getting the token
-			while (System.Array.IndexOf(delimiters,this.chars[this.currentPos]) == -1)
-			{
-				token+=this.chars[this.currentPos];
-				//the last one is not a delimiter
-				if (++this.currentPos == this.chars.Length)
-					break;
-			}
-			return token;
-		}
-
-				
-		/// <summary>
-		/// Determines if there are more tokens to return from the source string
-		/// </summary>
-		/// <returns>True or false, depending if there are more tokens</returns>
-		public bool HasMoreTokens()
-		{
-			//keeping the current pos
-			long pos = this.currentPos;
-			
-			try
-			{
-				this.NextToken();
-			}
-			catch (System.ArgumentOutOfRangeException)
-			{				
-				return false;
-			}
-			finally
-			{
-				this.currentPos = pos;
-			}
-			return true;
-		}
-
-		/// <summary>
-		/// Remaining tokens count
-		/// </summary>
-		public int Count
-		{
-			get
-			{
-				//keeping the current pos
-				long pos = this.currentPos;
-				int i = 0;
-			
-				try
-				{
-					while (true)
-					{
-						this.NextToken();
-						i++;
-					}
-				}
-				catch (System.ArgumentOutOfRangeException)
-				{				
-					this.currentPos = pos;
-					return i;
-				}
-			}
-		}
-
-		/// <summary>
-		///  Performs the same action as NextToken.
-		/// </summary>
-		public System.Object Current
-		{
-			get
-			{
-				return (Object) this.NextToken();
-			}		
-		}		
-		
-		/// <summary>
-		//  Performs the same action as HasMoreTokens.
-		/// </summary>
-		/// <returns>True or false, depending if there are more tokens</returns>
-		public bool MoveNext()
-		{
-			return this.HasMoreTokens();
-		}
-		
-		/// <summary>
-		/// Does nothing.
-		/// </summary>
-		public void  Reset()
-		{
-			;
-		}			
-	}
-}
Index: /trunk/sources/LibSVM/TemporaryCulture.cs
===================================================================
--- /trunk/sources/LibSVM/TemporaryCulture.cs	(revision 2415)
+++ /trunk/sources/LibSVM/TemporaryCulture.cs	(revision 2415)
@@ -0,0 +1,25 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Globalization;
+using System.Threading;
+
+namespace SVM
+{
+    internal static class TemporaryCulture
+    {
+        private static CultureInfo _culture;
+
+        public static void Start()
+        {
+            _culture = Thread.CurrentThread.CurrentCulture;
+            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+        }
+
+        public static void Stop()
+        {
+            Thread.CurrentThread.CurrentCulture = _culture;
+        }
+    }
+}
Index: /trunk/sources/LibSVM/Training.cs
===================================================================
--- /trunk/sources/LibSVM/Training.cs	(revision 2414)
+++ /trunk/sources/LibSVM/Training.cs	(revision 2415)
@@ -23,49 +23,52 @@
 namespace SVM
 {
-    /// <remarks>
+    /// <summary>
     /// Class containing the routines to train SVM models.
-    /// </remarks>
+    /// </summary>
     public static class Training
     {
+        /// <summary>
+        /// Whether the system will output information to the console during the training process.
+        /// </summary>
+        public static bool IsVerbose
+        {
+            get
+            {
+                return Procedures.IsVerbose;
+            }
+            set
+            {
+                Procedures.IsVerbose = value;
+            }
+        }
+
         private static double doCrossValidation(Problem problem, Parameter parameters, int nr_fold)
         {
             int i;
             double[] target = new double[problem.Count];
-            Dictionary<int, double>[] confidence = new Dictionary<int, double>[problem.Count];
-            Procedures.svm_cross_validation(problem, parameters, nr_fold, target, confidence);
-            if (parameters.Probability)
-            {
-                List<RankPair> ranks = new List<RankPair>();
-                for (i = 0; i < target.Length; i++)
-                    ranks.Add(new RankPair(confidence[i][1], problem.Y[i]));
-                PerformanceEvaluator eval = new PerformanceEvaluator(ranks);
-                return eval.AuC*eval.AP;
+            Procedures.svm_cross_validation(problem, parameters, nr_fold, target);
+            int total_correct = 0;
+            double total_error = 0;
+            double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
+            if (parameters.SvmType == SvmType.EPSILON_SVR || parameters.SvmType == SvmType.NU_SVR)
+            {
+                for (i = 0; i < problem.Count; i++)
+                {
+                    double y = problem.Y[i];
+                    double v = target[i];
+                    total_error += (v - y) * (v - y);
+                    sumv += v;
+                    sumy += y;
+                    sumvv += v * v;
+                    sumyy += y * y;
+                    sumvy += v * y;
+                }
+                return(problem.Count * sumvy - sumv * sumy) / (Math.Sqrt(problem.Count * sumvv - sumv * sumv) * Math.Sqrt(problem.Count * sumyy - sumy * sumy));
             }
             else
-            {
-                int total_correct = 0;
-                double total_error = 0;
-                double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
-                if (parameters.SvmType == SvmType.EPSILON_SVR || parameters.SvmType == SvmType.NU_SVR)
-                {
-                    for (i = 0; i < problem.Count; i++)
-                    {
-                        double y = problem.Y[i];
-                        double v = target[i];
-                        total_error += (v - y) * (v - y);
-                        sumv += v;
-                        sumy += y;
-                        sumvv += v * v;
-                        sumyy += y * y;
-                        sumvy += v * y;
-                    }
-                }
-                else
-                    for (i = 0; i < problem.Count; i++)
-                        if (target[i] == problem.Y[i])
-                            ++total_correct;
-                return (double)total_correct / problem.Count;
-            }
-
+                for (i = 0; i < problem.Count; i++)
+                    if (target[i] == problem.Y[i])
+                        ++total_correct;
+            return (double)total_correct / problem.Count;
         }
         /// <summary>
@@ -96,6 +99,8 @@
         public static double PerformCrossValidation(Problem problem, Parameter parameters, int nrfold)
         {
-            Procedures.svm_check_parameter(problem, parameters);
-            return doCrossValidation(problem, parameters, nrfold);
+            string error = Procedures.svm_check_parameter(problem, parameters);
+            if (error == null)
+                return doCrossValidation(problem, parameters, nrfold);
+            else throw new Exception(error);
         }
 
@@ -108,7 +113,9 @@
         public static Model Train(Problem problem, Parameter parameters)
         {
-            Procedures.svm_check_parameter(problem, parameters);
-
-            return Procedures.svm_train(problem, parameters);
+            string error = Procedures.svm_check_parameter(problem, parameters);
+
+            if (error == null)
+                return Procedures.svm_train(problem, parameters);
+            else throw new Exception(error);
         }
 
@@ -190,18 +197,5 @@
 
                     case 'w':
-                        ++parameters.WeightCount;
-                        {
-                            int[] old = parameters.WeightLabels;
-                            parameters.WeightLabels = new int[parameters.WeightCount];
-                            Array.Copy(old, 0, parameters.WeightLabels, 0, parameters.WeightCount - 1);
-                        }
-                        {
-                            double[] old = parameters.Weights;
-                            parameters.Weights = new double[parameters.WeightCount];
-                            Array.Copy(old, 0, parameters.Weights, 0, parameters.WeightCount - 1);
-                        }
-
-                        parameters.WeightLabels[parameters.WeightCount - 1] = int.Parse(args[i - 1].Substring(2));
-                        parameters.Weights[parameters.WeightCount - 1] = double.Parse(args[i]);
+                        parameters.Weights[int.Parse(args[i - 1].Substring(2))] = double.Parse(args[1]);
                         break;
 
