2015-05-20 4 views
1

Я изучаю C# и пытаюсь реализовать универсальный класс RandomVar наряду с некоторыми методами вычисления общей статистики как практики. Я хотел бы иметь возможность сформировать произвольную совместную вероятность RandomVariable из ее компонентов, создав новую переменную размерности N, где N передается в конструктор. Я хотел бы реализовать случайный Var X как два одномерных списка двойников, а randomVar XY - не как два списка длины n^2, а как randomVar типа double [] [], которые в противном случае могут по-прежнему использовать все те же методы (ExpectedValue, ковариация и т. д.).Передача размера массива в качестве параметра в C#

У меня возникли проблемы с этим. Помимо первого наивного подхода (который имел много копий и склейки), я пробовал наследовать из базового класса RandomVar в класс JointRandomVar - все еще много копирования. Теперь я пытаюсь использовать массивы вероятностей и результатов класса RandomVar как Generics типа List - это, однако, создает множество проблем, поскольку я не могу понять, как писать методы адаптивным способом (метод std_Dev может " t итерации по пути, в котором он нуждается, в общем, поэтому мне нужен гибкий способ определения метода, так что если «размерность» случайного Var равно 2, метод std_Dev будет выполнять двойной цикл или сгладить массив для процесса итерации).

Хотите получить помощь от более опытных программистов - наличие массивов вероятностей/результатов Список наилучшего способа передать такой параметр?

Большое спасибо за вашу помощь.

EDIT: Вот версия кода для всех парных, поэтому люди могут читать ее, поскольку не обновленная версия казалась более запутанной для людей. Я бы хотел, чтобы все эти методы работали над объектами типа double [] для любого измерения массива, и было возможно создать экземпляр класса с _values ​​и _probs, имеющими любое измерение.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Chapter_3_GUI 
{ 
    class RandomVar 
    { 
     private double[] _values; 
     private double[] _probs; 
     private double _mean; 
     private double _stddev; 
     private int _length; 
     private double _evalue; 

     public RandomVar(double[] values, double[] probs) 
     { 
      _values = values; 
      _probs = probs; 
      _mean = meanCalc(_values); 
      _stddev = stddevCalc(_values, _mean); 
      _length = _values.Length; 
      _evalue = expectedVal(_probs, _values, _length); 
     } 

     public double[] Values 
     { 
      get { return _values; } 
      set { _values = value; } 
     } 

     public double Mean 
     { 
      get { return _mean; } 
     } 

     public double Stdev 
     { 
      get { return _stddev; } 
     } 

     public static double meanCalc(double[] var) 
     { 
      double mean = var.Sum(); 
      return mean; 
     } 

     public static double stddevCalc(double[] var, double mean) 
     { 
      double[] varianceArr = new double[var.Length]; 
      for (int i = 0; i <= var.Length; i++) 
       varianceArr[i] = (var[i] - mean) * (var[i] - mean); 
       double variance = varianceArr.Sum(); 
       double stddev = Math.Sqrt(variance); 
       return stddev; 
      { 

      } 
     } 

     public static double[][] multiplyProbs(RandomVar X, RandomVar Y, double[][] cprobMatrix) 
     { 
      double[][] probArr = new double[X._length][Y._length]; 
      for (int i=0; i <= probArr.Length; i++) 
      { 
       for (int j =0; j <= probArr.Length; j++) 
       { 
        probArr[i][j] = Y._probs[j] * cprobMatrix[i][j]; 
       } 
      } 
      return probArr; 
     } 

     public static RandomVar multiplyVars(RandomVar X, RandomVar Y, Func<double,double> f) 
     { 
      double[][] productArr = new double[X._length][Y._length]; 
      for (int i=0; i<= productArr.Length; i++) 
      { 
       for (int j=0; j <= productArr.Length; i=j++) 
       { 
        productArr[i][j] = f(X._values[i], Y._values[j]); 
       } 
      } 
      double[][] probArr = multiplyProbs(X, Y, cprobMatrix); 
      RandomVar product = new RandomVar(productArr, probArr); 
      return product; 
     } 

     public static double expectedVal(double[] _probs, double[] _values, int _length) 
     { 
      double[] expectedArr = new double[_length]; 
      for (int i = 0; i <= expectedArr.Length; i++) 
      { 
       expectedArr[i] = _probs[i] * _values[i]; 
      } 
      double evalue = expectedArr.Sum(); 
      return evalue; 

     } 

     public static double covarianceCalc(RandomVar X, RandomVar Y, Func<double, double> f) 
     { 
      RandomVar VarXY = multiplyVars(X, Y, f); 
      double correlation = expectedVal(VarXY._probs, VarXY._values, VarXY._length); 
      double covariance = correlation - (X._mean * Y._mean); 
      return covariance; 
     } 

    } 
} 
+0

Возможно, вам будет оказана дополнительная помощь, если вы включите свои усилия (даже если это не работает), чем описание того, что вы хотите. –

+3

Трудно сказать, что у вас есть только из описания естественного языка. Подумайте, включая ваш код в свой вопрос. –

+0

Хорошо, я добавил код. Здесь много рудиментарного материала, так как изначально у меня просто были массивы случайных чисел/значений RandomVar, как type double [] – Quantumpencil

ответ

0

Является ли мощность каждого измерения одинаковым? Ваш комментарий о «рассматривая его как один длинный массив размера n^k» предлагает. То есть, n - это длина пар значений/вероятности в каждом измерении.

Другой вопрос, который у меня есть, является аргументом в пользу передачи значений и вероятностей в двух разных массивах? Если бы это было, я бы объявить struct, содержащие пары и т.д .:

struct ValueProbPair 
{ 
    public readonly double Value; 
    public readonly double Probability; 

    public ValueProbPair(double value, double probability) 
    { 
     Value = value; 
     Probability = probability; 
    } 
} 

Наконец, насколько ваш конкретный вопрос идет и hellip; ну, это не ясно, что конкретного вопрос есть. У вас, кажется, есть широкий вопрос относительно гибкого способа реализации этого.

Мне кажется, что самая большая проблема здесь (то есть контрольно-пропускной пункт с наименьшим интуитивно очевидным решение) в названии вашего вопроса:

Passing размерность массива в качестве параметра

Вы можете сделать это, то есть создать соответствующий объект массива, используя перегрузку Array.CreateInstance(Type, int[]). IMHO, он также будет работать лучше, если (но это не требуется) вы можете объединить пары значений/вероятности в один struct.

Другое большое предостережение заключается в том, что вы не получите преимущества оптимизации компилятора для доступа к элементам массива.Вы должны будете использовать, например. метод GetValue(), который, скорее всего, не позволит компилятору напрямую обращаться к элементам массива (оптимизация теоретически возможна, но мне кажется маловероятной).

Так, например, вы могли бы сделать что-то вроде:

Array Combine(ValueProbPair[] newDimension, Array previousDimensions) 
{ 
    int[] rankLengths = new int[previousDimensions.Rank + 1]; 

    for (int j = 0; j < previousDimensions.Rank; j++) 
    { 
     rankLengths[j] = previousDimensions.GetLength(j); 
    } 

    rankLengths[previousDimensions.Rank] = newDimension.Length; 

    Array result = Array.CreateInstance(typeof(ValueProbPair), rankLengths); 

    // then fill in your matrix using GetValue and SetValue to 
    // access individual array elements... 

    // Finally, return the new multi-dimensional array: 
    return result; 
} 

различных методов массива перегрузок, которые обращаются элементы используют params параметров массива, так что вы можете без особых трудностей написания кода, который может обрабатывать матрицы произвольного измерение. Например .:

IEnumerable<double> GetAllValues(Array source) 
{ 
    int[] index = new int[source.Rank]; 

    while (true) 
    { 
     yield return (double)source.GetValue(index); 

     int j = 0; 
     while (++index[j] == source.GetLength(j)) 
     { 
      index[j] = 0; 
      if (++j == index.Length) 
      { 
       yield break; 
      } 
     } 
    } 
} 

последнее замечание: для работы со значением/вероятности, в зависимости от сценария вы можете реально найти это имеет смысл делать все это с помощью словарей. Существуют различные осложнения, но основным строительным блоком будет Dictionary<double, object>, где значение равно double или другому Dictionary<double, object>. Затем, если вы ищете, например, объединенная вероятность, вам не нужно сканировать списки значений, а просто можете просто просмотреть их непосредственно как ключ в словаре.

+0

Большое спасибо - это было чрезвычайно полезно. Я принял ваш совет и повторно реализовал их пары prob/val как структуру. Сначала я закончу реализацию с использованием Array.CreateInstance (вместо массивов в стиле C), а затем попробую словарь для практики. Мне интересно (если вы знаете), как Array.CreateInstance реализует параметр размерности? Или где я могу найти эту информацию? Мне было бы интересно узнать. Укрепите это, как только у меня будет rep = p. Еще раз спасибо! – Quantumpencil

+0

_ «как Array.CreateInstance реализует параметр размерности» _ - Извините, я боюсь, что не понимаю вопроса. Что конкретно вы пытаетесь узнать об этом? Вы пытаетесь понять, как 'params' работает на C#? Или что-то другое? –

+0

Нет, мне интересно, как если бы я пытался реализовать свой собственный класс гибких массивов, мог бы реализовать перегрузку, такую ​​как Createinstance (x, int32 []), чтобы класс мог создавать массивы с произвольной размерностью (или, в более общем смысле, задаваться вопросом, как писать конструкторы/классы, чтобы параметры типа non могут влиять на тип экземпляра). – Quantumpencil

Смежные вопросы