Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
04/01/10 21:06:40 (14 years ago)
Author:
gkronber
Message:

Implemented basic framework for symbolic regression problems for HL 3.3. #938 (Data types and operators for regression problems)

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Dataset.cs

    r3246 r3253  
    11#region License Information
    22/* HeuristicLab
    3  * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    44 *
    55 * This file is part of HeuristicLab.
     
    2323using System.Collections.Generic;
    2424using System.Xml;
    25 using HeuristicLab.Core;
    26 using HeuristicLab.Data;
    2725using System.Globalization;
    2826using System.Text;
    2927using System.Linq;
    30 
    31 namespace HeuristicLab.DataAnalysis {
    32   public sealed class Dataset : ItemBase {
     28using HeuristicLab.Core;
     29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     30using HeuristicLab.Data;
     31using HeuristicLab.Common;
     32
     33namespace HeuristicLab.Problems.DataAnalysis {
     34  [Item("Dataset", "Represents a dataset containing data that should be analyzed.")]
     35  [StorableClass]
     36  public sealed class Dataset : NamedItem, IStringConvertibleMatrix {
    3337    private Dictionary<int, Dictionary<int, double>>[] cachedMeans;
    3438    private Dictionary<int, Dictionary<int, double>>[] cachedRanges;
     
    3943    }
    4044
    41     public Dataset(double[,] samples) {
     45    public Dataset(double[,] data)
     46      : base() {
    4247      Name = "-";
    43       Rows = samples.GetLength(0);
    44       Columns = samples.GetLength(1);
    45       double[] values = new double[Rows * Columns];
    46       int i = 0;
    47       for (int row = 0; row < Rows; row++) {
    48         for (int column = 0; column < columns; column++) {
    49           values[i++] = samples[row, column];
    50         }
    51       }
    52       Samples = values;
    53       fireChangeEvents = true;
    54     }
    55 
    56     #region Properties
    57     private string name;
    58     public string Name {
    59       get { return name; }
    60       set { name = value; }
    61     }
    62 
    63     private int rows;
    64     public int Rows {
    65       get { return rows; }
    66       set { rows = value; }
    67     }
    68 
    69     private int columns;
    70     public int Columns {
    71       get { return columns; }
    72       set {
    73         columns = value;
    74         if (variableNames == null || variableNames.Length != columns) {
    75           variableNames = new string[columns];
    76         }
    77       }
    78     }
    79 
    80     private string[] variableNames;
     48      Data = new DoubleMatrix(data);
     49      string formatString = new StringBuilder().Append('#', (int)Math.Log10(this.data.Columns) + 1).ToString(); // >= 100 variables => ###
     50      this.variableNames = new StringArray((from col in Enumerable.Range(1, this.data.Columns)
     51                                            select "Var" + col.ToString(formatString)).ToArray());
     52    }
     53
     54    private StringArray variableNames;
    8155    public IEnumerable<string> VariableNames {
    8256      get { return variableNames; }
    8357    }
    8458
    85     private double[] samples;
    86     public double[] Samples {
    87       get { return samples; }
     59    private DoubleMatrix data;
     60    private DoubleMatrix Data {
     61      get { return data; }
    8862      set {
    89         variableNames = Enumerable.Range(1, columns).Select(x => "Var" + x.ToString("###")).ToArray();
    90         scalingFactor = new double[columns];
    91         scalingOffset = new double[columns];
    92         for (int i = 0; i < scalingFactor.Length; i++) {
    93           scalingFactor[i] = 1.0;
    94           scalingOffset[i] = 0.0;
     63        if (data != value) {
     64          if (value == null) throw new ArgumentNullException();
     65          if (data != null) DeregisterDataEvents();
     66          this.data = value;
     67          RegisterDataEvents();
     68          OnReset(EventArgs.Empty);
    9569        }
    96         samples = value;
    97         cachedValuesInvalidated = true;
    98         if (fireChangeEvents) FireChanged();
    99       }
    100     }
    101 
    102     private bool fireChangeEvents = true;
    103     public bool FireChangeEvents {
    104       get { return fireChangeEvents; }
    105       set { fireChangeEvents = value; }
    106     }
    107 
    108     private double[] scalingFactor;
    109     public double[] ScalingFactor {
    110       get { return scalingFactor; }
     70      }
     71    }
     72
     73    private void RegisterDataEvents() {
     74      data.Reset += new EventHandler(data_Reset);
     75      data.ItemChanged += new EventHandler<EventArgs<int, int>>(data_ItemChanged);
     76    }
     77
     78    private void DeregisterDataEvents() {
     79      data.Reset -= new EventHandler(data_Reset);
     80      data.ItemChanged -= new EventHandler<EventArgs<int, int>>(data_ItemChanged);
     81    }
     82    // elementwise access
     83    public double this[int rowIndex, int columnIndex] {
     84      get { return data[rowIndex, columnIndex]; }
    11185      set {
    112         if (value.Length != scalingFactor.Length)
    113           throw new ArgumentException("Length of scaling factor array doesn't match number of variables");
    114         scalingFactor = value;
    115       }
    116     }
    117 
    118     private double[] scalingOffset;
    119     public double[] ScalingOffset {
    120       get { return scalingOffset; }
    121       set {
    122         if (value.Length != scalingOffset.Length)
    123           throw new ArgumentException("Length of scaling offset array doesn't match number of variables");
    124         scalingOffset = value;
    125       }
    126     }
    127     #endregion
    128 
    129     #region Modify and get values
    130     public double GetValue(int row, int column) {
    131       return samples[columns * row + column];
    132     }
    133 
    134     public double[] GetVariableValues(int variableIndex, int start, int end) {
     86        if (!value.Equals(data[rowIndex, columnIndex])) {
     87          data[rowIndex, columnIndex] = value;
     88          OnDataChanged(new EventArgs<int, int>(rowIndex, columnIndex));
     89        }
     90      }
     91    }
     92    // access to full columns
     93    public double[] this[string variableName] {
     94      get { return VariableValues(VariableIndex(variableName), 0, data.Rows); }
     95    }
     96
     97    public double[] VariableValues(int variableIndex, int start, int end) {
    13598      if (start < 0 || !(start <= end))
    13699        throw new ArgumentException("Start must be between 0 and end (" + end + ").");
    137       if (end > rows || end < start)
    138         throw new ArgumentException("End must be between start (" + start + ") and dataset rows (" + rows + ").");
     100      if (end > data.Rows || end < start)
     101        throw new ArgumentException("End must be between start (" + start + ") and dataset rows (" + data.Rows + ").");
    139102
    140103      double[] values = new double[end - start];
    141104      for (int i = 0; i < end - start; i++)
    142         values[i] = GetValue(i + start, variableIndex);
     105        values[i] = data[i + start, variableIndex];
    143106      return values;
    144107    }
    145108
    146     public double[] GetVariableValues(int variableIndex) {
    147       return GetVariableValues(variableIndex, 0, this.rows);
    148     }
    149 
    150     public double[] GetVariableValues(string variableName, int start, int end) {
    151       return GetVariableValues(GetVariableIndex(variableName), start, end);
    152     }
    153 
    154     public double[] GetVariableValues(string variableName) {
    155       return GetVariableValues(variableName, 0, this.rows);
    156     }
    157 
    158     public void SetValue(int i, int j, double v) {
    159       if (v != samples[columns * i + j]) {
    160         samples[columns * i + j] = v;
    161         cachedValuesInvalidated = true;
    162         if (fireChangeEvents) FireChanged();
    163       }
    164     }
    165 
    166     public IEnumerable<double> ReplaceVariableValues(int variableIndex, IEnumerable<double> newValues, int start, int end) {
    167       double[] oldValues = new double[end - start];
    168       for (int i = 0; i < end - start; i++) oldValues[i] = this.GetValue(i + start, variableIndex);
    169       if (newValues.Count() != end - start) throw new ArgumentException("The length of the new values sequence doesn't match the required length (number of replaced values)");
    170 
    171       int index = start;
    172       this.FireChangeEvents = false;
    173       foreach (double v in newValues) {
    174         this.SetValue(index++, variableIndex, v);
    175       }
    176       this.FireChangeEvents = true;
    177       this.FireChanged();
    178       return oldValues;
    179     }
    180 
    181     public IEnumerable<double> ReplaceVariableValues(string variableName, IEnumerable<double> newValues, int start, int end) {
    182       return ReplaceVariableValues(this.GetVariableIndex(variableName), newValues, start, end);
    183     }
    184     #endregion
     109    public double[] VariableValues(string variableName, int start, int end) {
     110      return VariableValues(VariableIndex(variableName), start, end);
     111    }
    185112
    186113    #region Variable name methods
    187     public string GetVariableName(int variableIndex) {
     114    public string VariableName(int variableIndex) {
    188115      return variableNames[variableIndex];
    189116    }
    190117
    191     public int GetVariableIndex(string variableName) {
     118    public int VariableIndex(string variableName) {
    192119      for (int i = 0; i < variableNames.Length; i++) {
    193120        if (variableNames[i].Equals(variableName)) return i;
     
    198125    public void SetVariableName(int variableIndex, string name) {
    199126      variableNames[variableIndex] = name;
    200       if (fireChangeEvents) FireChanged();
    201     }
    202 
    203     public bool ContainsVariableName(string variableName) {
    204       return this.variableNames.Contains(variableName);
    205     }
     127    }
     128
    206129    #endregion
    207130
    208     public override IView CreateView() {
    209       return new DatasetView(this);
    210     }
    211 
    212 
    213     #region Variable statistics
    214     public double GetMean(string variableName) {
    215       return GetMean(GetVariableIndex(variableName));
    216     }
    217 
    218     public double GetMean(string variableName, int start, int end) {
    219       return GetMean(GetVariableIndex(variableName), start, end);
    220     }
    221 
    222     public double GetMean(int column) {
    223       return GetMean(column, 0, Rows);
    224     }
    225 
    226     public double GetMean(int column, int start, int end) {
     131    #region variable statistics
     132    public double Mean(string variableName) {
     133      return Mean(VariableIndex(variableName));
     134    }
     135
     136    public double Mean(string variableName, int start, int end) {
     137      return Mean(VariableIndex(variableName), start, end);
     138    }
     139
     140    public double Mean(int variableIndex) {
     141      return Mean(variableIndex, 0, data.Rows);
     142    }
     143
     144    public double Mean(int variableIndex, int start, int end) {
    227145      if (cachedValuesInvalidated) CreateDictionaries();
    228       if (!cachedMeans[column].ContainsKey(start) || !cachedMeans[column][start].ContainsKey(end)) {
    229         double[] values = new double[end - start];
    230         for (int sample = start; sample < end; sample++) {
    231           values[sample - start] = GetValue(sample, column);
    232         }
    233         double mean = Statistics.Mean(values);
    234         if (!cachedMeans[column].ContainsKey(start)) cachedMeans[column][start] = new Dictionary<int, double>();
    235         cachedMeans[column][start][end] = mean;
     146      if (!cachedMeans[variableIndex].ContainsKey(start) || !cachedMeans[variableIndex][start].ContainsKey(end)) {
     147        double mean = VariableValues(variableIndex, start, end).Average();
     148        if (!cachedMeans[variableIndex].ContainsKey(start)) cachedMeans[variableIndex][start] = new Dictionary<int, double>();
     149        cachedMeans[variableIndex][start][end] = mean;
    236150        return mean;
    237151      } else {
    238         return cachedMeans[column][start][end];
    239       }
    240     }
    241 
    242     public double GetRange(string variableName) {
    243       return GetRange(this.GetVariableIndex(variableName));
    244     }
    245 
    246     public double GetRange(int column) {
    247       return GetRange(column, 0, Rows);
    248     }
    249 
    250     public double GetRange(string variableName, int start, int end) {
    251       return GetRange(this.GetVariableIndex(variableName), start, end);
    252     }
    253 
    254     public double GetRange(int column, int start, int end) {
     152        return cachedMeans[variableIndex][start][end];
     153      }
     154    }
     155
     156    public double Range(string variableName) {
     157      return Range(VariableIndex(variableName));
     158    }
     159
     160    public double Range(int variableIndex) {
     161      return Range(variableIndex, 0, data.Rows);
     162    }
     163
     164    public double Range(string variableName, int start, int end) {
     165      return Range(VariableIndex(variableName), start, end);
     166    }
     167
     168    public double Range(int variableIndex, int start, int end) {
    255169      if (cachedValuesInvalidated) CreateDictionaries();
    256       if (!cachedRanges[column].ContainsKey(start) || !cachedRanges[column][start].ContainsKey(end)) {
    257         double[] values = new double[end - start];
    258         for (int sample = start; sample < end; sample++) {
    259           values[sample - start] = GetValue(sample, column);
    260         }
    261         double range = Statistics.Range(values);
    262         if (!cachedRanges[column].ContainsKey(start)) cachedRanges[column][start] = new Dictionary<int, double>();
    263         cachedRanges[column][start][end] = range;
     170      if (!cachedRanges[variableIndex].ContainsKey(start) || !cachedRanges[variableIndex][start].ContainsKey(end)) {
     171        var values = VariableValues(variableIndex, start, end);
     172        double range = values.Max() - values.Min();
     173        if (!cachedRanges[variableIndex].ContainsKey(start)) cachedRanges[variableIndex][start] = new Dictionary<int, double>();
     174        cachedRanges[variableIndex][start][end] = range;
    264175        return range;
    265176      } else {
    266         return cachedRanges[column][start][end];
    267       }
    268     }
    269 
    270     public double GetMaximum(string variableName) {
    271       return GetMaximum(this.GetVariableIndex(variableName));
    272     }
    273 
    274     public double GetMaximum(int column) {
    275       return GetMaximum(column, 0, Rows);
    276     }
    277 
    278     public double GetMaximum(string variableName, int start, int end) {
    279       return GetMaximum(this.GetVariableIndex(variableName), start, end);
    280     }
    281 
    282     public double GetMaximum(int column, int start, int end) {
    283       double max = Double.NegativeInfinity;
    284       for (int i = start; i < end; i++) {
    285         double val = GetValue(i, column);
    286         if (!double.IsNaN(val) && val > max) max = val;
    287       }
    288       return max;
    289     }
    290 
    291     public double GetMinimum(string variableName) {
    292       return GetMinimum(GetVariableIndex(variableName));
    293     }
    294 
    295     public double GetMinimum(int column) {
    296       return GetMinimum(column, 0, Rows);
    297     }
    298 
    299     public double GetMinimum(string variableName, int start, int end) {
    300       return GetMinimum(this.GetVariableIndex(variableName), start, end);
    301     }
    302 
    303     public double GetMinimum(int column, int start, int end) {
    304       double min = Double.PositiveInfinity;
    305       for (int i = start; i < end; i++) {
    306         double val = GetValue(i, column);
    307         if (!double.IsNaN(val) && val < min) min = val;
    308       }
    309       return min;
    310     }
    311 
    312     public int CountMissingValues(string variableName) {
    313       return CountMissingValues(this.GetVariableIndex(variableName));
    314     }
    315     public int CountMissingValues(int column) {
    316       return CountMissingValues(column, 0, Rows);
    317     }
    318 
    319     public int CountMissingValues(string variableName, int start, int end) {
    320       return CountMissingValues(this.GetVariableIndex(variableName), start, end);
    321     }
    322 
    323     public int CountMissingValues(int column, int start, int end) {
    324       int n = 0;
    325       for (int i = start; i < end; i++) {
    326         double val = GetValue(i, column);
    327         if (double.IsNaN(val)) n++;
    328       }
    329       return n;
     177        return cachedRanges[variableIndex][start][end];
     178      }
     179    }
     180
     181    public double Max(string variableName) {
     182      return Max(VariableIndex(variableName));
     183    }
     184
     185    public double Max(int variableIndex) {
     186      return Max(variableIndex, 0, data.Rows);
     187    }
     188
     189    public double Max(string variableName, int start, int end) {
     190      return Max(VariableIndex(variableName), start, end);
     191    }
     192
     193    public double Max(int variableIndex, int start, int end) {
     194      return VariableValues(variableIndex, start, end).Max();
     195    }
     196
     197    public double Min(string variableName) {
     198      return Min(VariableIndex(variableName));
     199    }
     200
     201    public double Min(int variableIndex) {
     202      return Min(variableIndex, 0, data.Rows);
     203    }
     204
     205    public double Min(string variableName, int start, int end) {
     206      return Min(VariableIndex(variableName), start, end);
     207    }
     208
     209    public double Min(int variableIndex, int start, int end) {
     210      return VariableValues(variableIndex, start, end).Min();
     211    }
     212
     213    public int MissingValues(string variableName) {
     214      return MissingValues(VariableIndex(variableName));
     215    }
     216    public int MissingValues(int variableIndex) {
     217      return MissingValues(variableIndex, 0, data.Rows);
     218    }
     219
     220    public int MissingValues(string variableName, int start, int end) {
     221      return MissingValues(VariableIndex(variableName), start, end);
     222    }
     223
     224    public int MissingValues(int variableIndex, int start, int end) {
     225      return VariableValues(variableIndex, start, end).Count(x => double.IsNaN(x));
    330226    }
    331227
    332228    #endregion
    333 
    334     internal void ScaleVariable(int column) {
    335       if (scalingFactor[column] == 1.0 && scalingOffset[column] == 0.0) {
    336         double min = GetMinimum(column);
    337         double max = GetMaximum(column);
    338         double range = max - min;
    339         if (range == 0) ScaleVariable(column, 1.0, -min);
    340         else ScaleVariable(column, 1.0 / range, -min);
    341       }
    342       cachedValuesInvalidated = true;
    343       if (fireChangeEvents) FireChanged();
    344     }
    345 
    346     internal void ScaleVariable(int column, double factor, double offset) {
    347       scalingFactor[column] = factor;
    348       scalingOffset[column] = offset;
    349       for (int i = 0; i < Rows; i++) {
    350         double origValue = samples[i * columns + column];
    351         samples[i * columns + column] = (origValue + offset) * factor;
    352       }
    353       cachedValuesInvalidated = true;
    354       if (fireChangeEvents) FireChanged();
    355     }
    356 
    357     internal void UnscaleVariable(int column) {
    358       if (scalingFactor[column] != 1.0 || scalingOffset[column] != 0.0) {
    359         for (int i = 0; i < rows; i++) {
    360           double scaledValue = samples[i * columns + column];
    361           samples[i * columns + column] = scaledValue / scalingFactor[column] - scalingOffset[column];
    362         }
    363         scalingFactor[column] = 1.0;
    364         scalingOffset[column] = 0.0;
    365       }
    366       cachedValuesInvalidated = true;
    367       if (fireChangeEvents) FireChanged();
    368     }
    369229
    370230    private void CreateDictionaries() {
    371231      // keep a means and ranges dictionary for each column (possible target variable) of the dataset.
    372       cachedMeans = new Dictionary<int, Dictionary<int, double>>[columns];
    373       cachedRanges = new Dictionary<int, Dictionary<int, double>>[columns];
    374       for (int i = 0; i < columns; i++) {
     232      cachedMeans = new Dictionary<int, Dictionary<int, double>>[data.Columns];
     233      cachedRanges = new Dictionary<int, Dictionary<int, double>>[data.Columns];
     234      for (int i = 0; i < data.Columns; i++) {
    375235        cachedMeans[i] = new Dictionary<int, Dictionary<int, double>>();
    376236        cachedRanges[i] = new Dictionary<int, Dictionary<int, double>>();
     
    379239    }
    380240
    381     #region persistence
    382     public override object Clone(IDictionary<Guid, object> clonedObjects) {
    383       Dataset clone = new Dataset();
    384       clonedObjects.Add(Guid, clone);
    385       double[] cloneSamples = new double[rows * columns];
    386       Array.Copy(samples, cloneSamples, samples.Length);
    387       clone.rows = rows;
    388       clone.columns = columns;
    389       clone.Samples = cloneSamples;
    390       clone.Name = Name;
    391       clone.variableNames = new string[variableNames.Length];
    392       Array.Copy(variableNames, clone.variableNames, variableNames.Length);
    393       Array.Copy(scalingFactor, clone.scalingFactor, columns);
    394       Array.Copy(scalingOffset, clone.scalingOffset, columns);
     241    public override IDeepCloneable Clone(Cloner cloner) {
     242      Dataset clone = (Dataset)base.Clone(cloner);
     243      clone.data = (DoubleMatrix)data.Clone(cloner);
     244      clone.variableNames = (StringArray)variableNames.Clone(cloner);
    395245      return clone;
    396246    }
    397247
    398     public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
    399       XmlNode node = base.GetXmlNode(name, document, persistedObjects);
    400       XmlAttribute problemName = document.CreateAttribute("Name");
    401       problemName.Value = Name;
    402       node.Attributes.Append(problemName);
    403       XmlAttribute dim1 = document.CreateAttribute("Dimension1");
    404       dim1.Value = rows.ToString(CultureInfo.InvariantCulture.NumberFormat);
    405       node.Attributes.Append(dim1);
    406       XmlAttribute dim2 = document.CreateAttribute("Dimension2");
    407       dim2.Value = columns.ToString(CultureInfo.InvariantCulture.NumberFormat);
    408       node.Attributes.Append(dim2);
    409       XmlAttribute variableNames = document.CreateAttribute("VariableNames");
    410       variableNames.Value = GetVariableNamesString();
    411       node.Attributes.Append(variableNames);
    412       XmlAttribute scalingFactorsAttribute = document.CreateAttribute("ScalingFactors");
    413       scalingFactorsAttribute.Value = GetString(scalingFactor);
    414       node.Attributes.Append(scalingFactorsAttribute);
    415       XmlAttribute scalingOffsetsAttribute = document.CreateAttribute("ScalingOffsets");
    416       scalingOffsetsAttribute.Value = GetString(scalingOffset);
    417       node.Attributes.Append(scalingOffsetsAttribute);
    418       node.InnerText = ToString(CultureInfo.InvariantCulture.NumberFormat);
    419       return node;
    420     }
    421 
    422     public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
    423       base.Populate(node, restoredObjects);
    424       Name = node.Attributes["Name"].Value;
    425       rows = int.Parse(node.Attributes["Dimension1"].Value, CultureInfo.InvariantCulture.NumberFormat);
    426       columns = int.Parse(node.Attributes["Dimension2"].Value, CultureInfo.InvariantCulture.NumberFormat);
    427 
    428       variableNames = ParseVariableNamesString(node.Attributes["VariableNames"].Value);
    429       if (node.Attributes["ScalingFactors"] != null)
    430         scalingFactor = ParseDoubleString(node.Attributes["ScalingFactors"].Value);
    431       else {
    432         scalingFactor = new double[columns]; // compatibility with old serialization format
    433         for (int i = 0; i < scalingFactor.Length; i++) scalingFactor[i] = 1.0;
    434       }
    435       if (node.Attributes["ScalingOffsets"] != null)
    436         scalingOffset = ParseDoubleString(node.Attributes["ScalingOffsets"].Value);
    437       else {
    438         scalingOffset = new double[columns]; // compatibility with old serialization format
    439         for (int i = 0; i < scalingOffset.Length; i++) scalingOffset[i] = 0.0;
    440       }
    441 
    442       string[] tokens = node.InnerText.Split(';');
    443       if (tokens.Length != rows * columns) throw new FormatException();
    444       samples = new double[rows * columns];
    445       for (int row = 0; row < rows; row++) {
    446         for (int column = 0; column < columns; column++) {
    447           if (double.TryParse(tokens[row * columns + column], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out samples[row * columns + column]) == false) {
    448             throw new FormatException("Can't parse " + tokens[row * columns + column] + " as double value.");
     248    #region events
     249    public event EventHandler<EventArgs<int, int>> DataChanged;
     250    private void OnDataChanged(EventArgs<int, int> e) {
     251      cachedValuesInvalidated = true;
     252
     253      var listeners = DataChanged;
     254      if (listeners != null) listeners(this, e);
     255    }
     256    public event EventHandler Reset;
     257    private void OnReset(EventArgs e) {
     258      cachedValuesInvalidated = true;
     259
     260      var listeners = Reset;
     261      if (listeners != null) listeners(this, e);
     262    }
     263
     264    private void data_ItemChanged(object sender, EventArgs<int, int> e) {
     265      OnDataChanged(e);
     266    }
     267
     268    private void data_Reset(object sender, EventArgs e) {
     269      OnReset(e);
     270    }
     271    #endregion
     272
     273    #region IStringConvertibleMatrix Members
     274
     275    public int Rows {
     276      get {
     277        return data.Rows + 1;
     278      }
     279      set {
     280        if (value == 0) throw new ArgumentException("Number of rows must be at least one (for variable names)");
     281        if (value - 1 != data.Rows) {
     282          var newValues = new double[value - 1, data.Columns];
     283          for (int row = 0; row < Math.Min(data.Rows, value - 1); row++) {
     284            for (int column = 0; column < data.Columns; column++) {
     285              newValues[row, column] = data[row, column];
     286            }
    449287          }
     288          Data = new DoubleMatrix(newValues);
    450289        }
    451290      }
    452291    }
    453292
    454     public override string ToString() {
    455       return ToString(CultureInfo.CurrentCulture.NumberFormat);
    456     }
    457 
    458     private string ToString(NumberFormatInfo format) {
    459       StringBuilder builder = new StringBuilder();
    460       for (int row = 0; row < rows; row++) {
    461         for (int column = 0; column < columns; column++) {
    462           builder.Append(";");
    463           builder.Append(samples[row * columns + column].ToString("r", format));
     293    public int Columns {
     294      get {
     295        return data.Columns;
     296      }
     297      set {
     298        if (value != data.Columns) {
     299          var newValues = new double[data.Rows, value];
     300          var newVariableNames = new string[value];
     301          for (int row = 0; row < data.Rows; row++) {
     302            for (int column = 0; column < Math.Min(value, data.Columns); column++) {
     303              newValues[row, column] = data[row, column];
     304            }
     305          }
     306          string formatString = new StringBuilder().Append('#', (int)Math.Log10(value) + 1).ToString(); // >= 100 variables => ###
     307          for (int column = 0; column < value; column++) {
     308            if (column < data.Columns)
     309              newVariableNames[column] = variableNames[column];
     310            else
     311              newVariableNames[column] = "Var" + column.ToString(formatString);
     312          }
     313          variableNames = new StringArray(newVariableNames);
     314          Data = new DoubleMatrix(newValues);
    464315        }
    465316      }
    466       if (builder.Length > 0) builder.Remove(0, 1);
    467       return builder.ToString();
    468     }
    469 
    470     private string GetVariableNamesString() {
    471       string s = "";
    472       for (int i = 0; i < variableNames.Length; i++) {
    473         s += variableNames[i] + "; ";
    474       }
    475 
    476       if (variableNames.Length > 0) {
    477         s = s.TrimEnd(';', ' ');
    478       }
    479       return s;
    480     }
    481     private string GetString(double[] xs) {
    482       string s = "";
    483       for (int i = 0; i < xs.Length; i++) {
    484         s += xs[i].ToString("r", CultureInfo.InvariantCulture) + "; ";
    485       }
    486 
    487       if (xs.Length > 0) {
    488         s = s.TrimEnd(';', ' ');
    489       }
    490       return s;
    491     }
    492 
    493     private string[] ParseVariableNamesString(string p) {
    494       p = p.Trim();
    495       string[] tokens = p.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
    496       for (int i = 0; i < tokens.Length; i++) tokens[i] = tokens[i].Trim();
    497       return tokens;
    498     }
    499     private double[] ParseDoubleString(string s) {
    500       s = s.Trim();
    501       string[] ss = s.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
    502       double[] xs = new double[ss.Length];
    503       for (int i = 0; i < xs.Length; i++) {
    504         xs[i] = double.Parse(ss[i], CultureInfo.InvariantCulture);
    505       }
    506       return xs;
    507     }
     317    }
     318
     319    public bool Validate(string value, out string errorMessage) {
     320      errorMessage = string.Empty;
     321      return true;
     322    }
     323
     324    public string GetValue(int rowIndex, int columnIndex) {
     325      if (rowIndex == 0) {
     326        // return variable name
     327        return variableNames[columnIndex];
     328      } else {
     329        return data[rowIndex - 1, columnIndex].ToString();
     330      }
     331    }
     332
     333    public bool SetValue(string value, int rowIndex, int columnIndex) {
     334      if (rowIndex == 0) {
     335        // set variable name
     336        variableNames[columnIndex] = value;
     337        return true;
     338      } else {
     339        double v;
     340        if (double.TryParse(value, out v)) {
     341          data[rowIndex - 1, columnIndex] = v;
     342          return true;
     343        } else return false;
     344      }
     345    }
     346
     347    public event EventHandler<EventArgs<int, int>> ItemChanged;
     348
    508349    #endregion
    509350  }
Note: See TracChangeset for help on using the changeset viewer.