How to use 3D array's Sum function? - c#

I have a 3d array double[][][] arr, which it's actually an array of double[][] matrix, I want to Sum all the matrices inside the array, I was going to write a Sum function, but I saw this function which I don't know how to use it in multidimensional array and I'm not sure if it's what I'm looking for.
double[][][] m;
m.Sum<double>();

The problem is that it can't be Sum<double> because double[][][] implements IEnumerable<double[][]>. So you can have two solutions here, using the Aggregate LINQ method:
1) Write a method double[][] AddMatrices(double[][] m1, double[][] m2) and then use:
var result = arr.Aggregate(AddMatrices);
2) Create a class Matrix (or just download one of many existing solutions), which has Add method, or overloaded operator+ and then similarly:
var result = arr.Aggregate(Matrix.Add);
The latter is of course advised, since it's explicit and thus more readable.
And to answer your question directly: no Sum doesn't have multidimensional equivalent out-of-box, as you can see looking at its overload list in the documentation.

double[][][] m = new double[2][][];
m[0] = new double[2][];
m[1] = new double[2][];
m[0][0] = new double[2];
m[0][1] = new double[2];
m[1][0] = new double[2];
m[1][1] = new double[2];
m[0][0][0] = 0;
m[0][0][1] = 1;
m[0][1][0] = 2;
m[0][1][1] = 3;
m[1][0][0] = 4;
m[1][0][1] = 5;
m[1][1][0] = 6;
m[1][1][1] = 7;
var summ = m.SelectMany(f => f.SelectMany(g => g)).Sum(); // summ = 28.0
double[, ,] n = new double[2, 2, 2];
n[0, 0, 0] = 0;
n[0, 0, 1] = 1;
n[0, 1, 0] = 2;
n[0, 1, 1] = 3;
n[1, 0, 0] = 4;
n[1, 0, 1] = 5;
n[1, 1, 0] = 6;
n[1, 1, 1] = 7;
var sumn = n.Cast<double>().Sum(); // sumn = 28.0

Related

Find all match positions in SIMD Avx.CompareEqual, or for a whole array while counting matches

I have a question if this is possible using SIMD instructions at all or if there could be some kind of Hybrid solution SIMD/Normal C# code solution to what I am trying to do or if it is not possible and will sacrifice to much speed of the SIMD instructions for it to be interesting.
My code counts how many 0,1,2,3 that exists in: inputArray (Micro Optimization of a 4-bucket histogram of a large array or list). Result is shown in: countArray
The correct answer to this is: 3,9,1,3.
My question now is this:
As seen we also have passed along: indexArray to the function. If we take 0 from inputArray as an example where we have 3 occurrences. We can see in the indexArray that those occurrences are at indexes: 9,43,5
I wonder if it is possible to add/collect this information in for example 4 buckets as well for each of the possible element values (0,1,2,3) in inputArray?
In the below code part we can see where the indexes for example: val = 1 is found: 0,9,10
I don't know if it is possible to catch those indexes somehow that could map/get the indexes from the indexArray?
The main goal to for example: ´0´ is to get an array in the end like this:
int[] indexes0 = new int[3]; //But we dont know that it will be 3 beforehand
indexes0[0] = 9;
indexes0[1] = 43;
indexes0[2] = 5;
[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]
// accumulate match counts into 4 vectors of 8-bit counters, one for each val
var v = Avx.LoadVector128(&fixedInput[0]);
for (byte val = 0; val < 4; val++)
{
//[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0] -CompareEqual to: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
var match = Avx.CompareEqual(v, Vector128.Create(val));
counts[val] = Avx.Subtract(counts[val], match); // count -= 0 or -1
}
(Please note: I have a Piledriver CPU that can't run AVX2)
Complete Code (simplified for an array that's only one vector-width long):
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
private void button3_Click(object sender, EventArgs e)
{
//Create 16 indexes with numbers between: 0-3. The goal is to count how many of those occurences we have for the numbers: 0-3
byte[] v1 = new byte[16]; int[] v2 = new int[16];
v1[0] = 0; v2[0] = 9;
v1[1] = 1; v2[1] = 12;
v1[2] = 2; v2[2] = 55;
v1[3] = 3; v2[3] = 23;
v1[4] = 1; v2[4] = 568;
v1[5] = 1; v2[5] = 4;
v1[6] = 1; v2[6] = 6;
v1[7] = 1; v2[7] = 1008;
v1[8] = 1; v2[8] = 188800;
v1[9] = 0; v2[9] = 43;
v1[10] = 0; v2[10] = 5;
v1[11] = 3; v2[11] = 2;
v1[12] = 1; v2[12] = 1;
v1[13] = 1; v2[13] = 58;
v1[14] = 1; v2[14] = 8;
v1[15] = 3; v2[15] = 15;
/*---------------*/
ReadOnlySpan<byte> inputArray = v1;
ReadOnlySpan<int> indexArray = v2;
//Call function
countElements(inputArray, indexArray);
}
// simplified for inputArray.Count == 16 exactly, no looping or cleanup
// shows counts, doesn't find positions at all
private unsafe static void countElements(ReadOnlySpan<byte> inputArray, ReadOnlySpan<int> indexArray)
{
int[,] indexes0123 = new int[,] { }; //Store arrays for indexes found for the numbers: 0,1,2,3 in the "indexArray"
//Below starts the SIMD calculations!
int[] countArray = new int[4];
Span<Vector128<byte>> counts = stackalloc Vector128<byte>[4];
Span<Vector128<UInt64>> sum64 = stackalloc Vector128<UInt64>[4];
unsafe
{
fixed (byte* fixedInput = inputArray)
{
var v = Avx.LoadVector128(&fixedInput[0]);
for (byte val = 0; val < 4; val++)
{
//[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0] -CompareEqual to: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
var match = Avx.CompareEqual(v, Vector128.Create(val));
counts[val] = Avx.Subtract(counts[val], match);
}
//Here SumAbsoluteDifferences
for (int i3 = 0; i3 < 4; i3++)
{
sum64[i3] = Sse2.Add(sum64[i3], Sse2.SumAbsoluteDifferences(counts[i3], Vector128<byte>.Zero).AsUInt64()); //sum64: <2,0,0,0,3,0,0,0>
}
//UnpackHigh and get the lower element from the Vector128<UInt64>
for (int i3 = 0; i3 < 4; i3++)
{
Vector128<UInt64> upper = Sse2.UnpackHigh(sum64[i3], sum64[i3]).AsUInt64(); //3
countArray[i3] += Sse2.Add(sum64[i3], upper).ToScalar();
}
//We now know how many 0,1,2,3 we have of each: (But we also need to collect which indexes from "indexlist" each of these 4 buckets has)
//3,9,1,3
MessageBox.Show(countArray[0] + "," + countArray[1] + "," + countArray[2] + "," + countArray[3]);
}
}
}

How can I sort multiple two dimensional arrays so that the first row is sorted into bins and the second row is summed up?

I am going to have a number of two-dimensional arrays that I would like to summarize into a single two-dimensional array. The first row is composed of doubles that represent mass, while the second row is composed of doubles that represent intensity.
//example 1 two-dimensional array
[145.56, 246.44, 346.55, 204.78]
[14, 30, 58, 49]
//example 2 two-dimensional array
[151.62, 223.18, 389.78, 266.96]
[67, 56, 23, 47]
I would like to summarize the two-dimensional arrays by sorting the mass doubles in the first row into bins of equal length, and then summing the pertinent intensity double up. So, assuming the mass bins had a length of 50, the summarized two-dimensional array using the two examples above would be:
//tentative example summarized two-dimensional array
[100-150, 150-200, 200-250, 250-300, 300-350, 350-400]
[14, 67, 135, 47, 58, 23 ]
I have so far tried to create a for loop that would first check which bin the mass would fall into by iterating over a nested for loop of the , and then add the intensity to previous intensity values.
double binSize = 50;
double[] binArray = new double[someNumberOfBins]
double[] summedIntensities= new double[numberOfTheirSummedIntensities];
for(i=0; i<twoDimensionalArray.GetLength(1); i++){
double currentMass= twoDimensionalArray[0,i];
for(j=0; j<binArray.GetLength(1); j++) {
if(currentMass> (binArray[j] - binSize) && currentMass <= (binArray[j] + binSize)) {
double currentIntensity = twoDimensionalArray[1,i];
summedIntensities[j] += currentIntensity;
}
}
//somehow combine the binArray with summedIntensities array into a two dimensional array
However, there are some problems in the a design of this algorithm. Firstly, I do not know how to set up the binArray so that the numbers in it properly reflect the range of in my two-dimensional arrays. I also am not sure how to combine the binArray with the summedIntensities array into a two-dimensional array, or whether this is even practical for this particular case.
Is there another way of making the binArray that is more fitting with my purpose of creating a summarized two-dimensional array, or are there any other glaring problems with this algorithm?
Here is my algorithm:
Note 1: in result array the first row will be '100', '150', '200'... You can construct a struct or use Dictionary<string,int> if you want it as "100-149", "150-199"...
Note 2: i calculated the interval as [100-149], [150,199], [200,249]... modify last condition to change it if you need to
static void Main(string[] args)
{
double[,] array1 = new double[2, 4] { { 145.56d, 246.44d, 346.55d, 204.78d }, { 14d, 30d, 58d, 49d } };
double[,] array2 = new double[2, 4] { { 151.62d, 223.18d, 389.78d, 266.96d }, { 67d, 56d, 23d, 47d } };
double[,] finalArray = DoWork(array1, array2,50);
}
private static double[,] DoWork(double[,] arrayLeft, double[,] arrayRight, int binLength)
{
//union of arrays
double[,] newArray = new double[2, arrayLeft.GetLength(1) + arrayRight.GetLength(1)]; //2x8 array
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < arrayLeft.GetLength(1); j++)
{
newArray[i, j] = arrayLeft[i, j];
}
for (int j = arrayLeft.GetLength(1); j < arrayLeft.GetLength(1) + arrayRight.GetLength(1); j++)
{
newArray[i, j] = arrayRight[i, j-4];
}
}
//sorting first row
for (int i = 0; i < newArray.GetLength(1)-1; i++)
{
for (int j = i+1; j < newArray.GetLength(1); j++)
{
if (newArray[0, i] > newArray[0, j])
{
double temp0 = newArray[0, j];
double temp1 = newArray[1, j];
newArray[0, j] = newArray[0, i];
newArray[1, j] = newArray[1, i];
newArray[0, i] = temp0;
newArray[1, i] = temp1;
}
}
}
//determine the number of bins and their intervals
double minMass = newArray[0, 0]; //145.56
double maxMass = newArray[0, newArray.GetLength(1) - 1]; //389.78
double minBinLowerValue = 0; //since you're working with mass i ignore the negative values
while (minBinLowerValue + binLength < minMass) minBinLowerValue += binLength; //100
double maxBinHigherValue = minBinLowerValue;
while (maxBinHigherValue < maxMass) maxBinHigherValue += binLength; //400
double numberOfBins = (maxBinHigherValue - minBinLowerValue) / binLength; //6
//creation of result array
double[,] resultArray = new double[2, Convert.ToInt32(numberOfBins)]; //2x6 array
//fill intervals to first row
for (int i = 0; i < resultArray.GetLength(1); i++)
{
resultArray[0, i] = minBinLowerValue + binLength * i;
}
//fill the sums
for (int i = 0; i < resultArray.GetLength(1); i++)
{
double sum = 0;
for (int j = 0; j < newArray.GetLength(1); j++)
{
if(resultArray[0,i] <= newArray[0,j] && resultArray[0, i] + binLength > newArray[0, j]) //modify this condition
{
sum += newArray[1, j];
}
}
resultArray[1, i] = sum;
}
return resultArray;
}
Here you go, I used a dictionary to store the summed values. The key is a bin number.
Note: If you want to make your solution better, I would use a class with 2 props (mass and intensity) I did not make this solution because am not sure if you have the freedom to have a class or if you are stuck with with input you got.
using System;
using System.Collections.Generic;
{
class Program
{
static void Main(string[] args)
{
double[] bins1 = { 145.56, 246.44, 346.55, 204.78 };
double[] values1 = { 14, 30, 58, 49 };
double[] bins2 = { 151.62, 223.18, 389.78, 266.96 };
double[] values2 = { 67, 56, 23, 47 };
int binSize = 50;
Dictionary<int, double> summedBins = new Dictionary<int, double>();
AddValuesToSummedBins(binSize, summedBins, bins1, values1);
AddValuesToSummedBins(binSize, summedBins, bins2, values2);
}
public static void AddValuesToSummedBins(int binSize, Dictionary<int, double> SummedBins, double[] Bins, double[] Values)
{
int i = 0;
foreach (double oneBin in Bins)
{
int binSet = binSize * ((int) oneBin / binSize);
if (!SummedBins.ContainsKey(binSet))
{
SummedBins.Add(binSet, Values[i]);
}
else
{
SummedBins[binSet] += Values[i];
}
i++;
}
}
}
}
If you are flexible about your data format, you can use LINQ to do this in a very small amount of code.
You would need to store your data pairs as a class with Mass and Intensity properties, instead of separate items in a 2D array.
Assuming this class to store your data:
public class DataElement
{
public double Mass { get; set; }
public double Intensity { get; set; }
}
You could use the following function:
public List<DataElement> Summarize(IEnumerable<DataElement> data, int range)
{
return data.GroupBy(de => Math.Floor(de.Mass / range) * range,
(range, g) => new DataElement {
Mass = range,
Intensity = g.Sum(d => d.Intensity)
})
.OrderBy(de => de.Mass)
.ToList();
}
This function takes all of your data as a single IEnumerable, and runs it thought LINQ's GroupBy function.
The first argument is an expression that determines how to group items together. For your purpose, I simply round down to the nearest multiple of the range argument (50 in your example, but anything should work).
The 2nd argument is an expression that returns the final output of a group, given the key of the group (the rounded down Mass), and the elements that were grouped together. I just return a new DataElement with e Mass of the rounded down Mass, and an Intensity equal to the Sum of the Intentities of the grouped item.
The result is then sorted by Mass before returning the result.
This produces the following output from the input you specified in the question (from LINQPad's Dump function):
You could use it like this (available as a LINQPad file):
void Main()
{
var data1 = new List<DataElement>{
new DataElement{Mass = 145.56, Intensity = 14},
new DataElement{Mass = 246.44, Intensity = 30},
new DataElement{Mass = 346.55, Intensity = 58},
new DataElement{Mass = 204.78, Intensity = 49},
};
var data2 = new List<DataElement>{
new DataElement{Mass = 151.62, Intensity = 67},
new DataElement{Mass = 223.18, Intensity = 56},
new DataElement{Mass = 389.78, Intensity = 23},
new DataElement{Mass = 266.96, Intensity = 47},
};
var result = Summarize(data1.Concat(data2), 50);
}

Defining an array list in c# unity.

I am trying to make an array list of integer values and run some basic math operations as seen below.
int dice1 = 4;
int dice2 = 3;
int dice3 = 6;
int dice4 = 4;
int dice 5 = 5;
ArrayList numbers = new ArrayList();
numbers[4] = dice5;
numbers[3] = dice4;
numbers[2] = dice3;
numbers[1] = dice2;
numbers[0] = dice1;
numbers[3] = numbers[3] * numbers[2];
However, the computer does not allow me to do this and produces an error "Operator "*" cannot be applied to operands of the type 'object' and 'object'". How do I fix this? I think that I have to define the array list as an array of integers... however I am not too sure. Please keep the answers simple as I am quite new to C# unity.
Thanks!
ArrayList stores everything as an 'object', basically the most basic type something can be in C#. You have a few options. If you want to keep using ArrayList, then you'll need to do cast the things you're multiplying, like:
numbers[3] = ((int)numbers[3]) * ((int)numbers[2])
Alternatively, you can ditch ArrayList and use the more modern List<> type. You need to add using System.Collections.Generic to the top, then your code will be like:
int dice1 = 4;
int dice2 = 3;
int dice3 = 6;
int dice4 = 4;
int dice5 = 5;
List<int> numbers = new List<int>(); //List contains ints only
numbers[4] = dice5;
numbers[3] = dice4;
numbers[2] = dice3;
numbers[1] = dice2;
numbers[0] = dice1;
numbers[3] = numbers[3] * numbers[2]; //Works as expected
Finally, if you know that your collection will only have a certain number of things, you can use an array instead. Your code will now be:
int dice1 = 4;
int dice2 = 3;
int dice3 = 6;
int dice4 = 4;
int dice5 = 5;
int[] numbers = new int[5]; //Creates an int array with 5 elements
//Meaning you can only access numbers[0] to numbers[4] inclusive
numbers[4] = dice5;
numbers[3] = dice4;
numbers[2] = dice3;
numbers[1] = dice2;
numbers[0] = dice1;
numbers[3] = numbers[3] * numbers[2]; //Works as expected
Avoid using array list
Use List<int> or int[]
Then the objects contained are typed instead of being object
You can do it in one line:
List<int> numbers = new List<int>{ 4, 3, 6, 4, 5 };
You need to parse the object to string then to int value then use it with * operator.But you firstly have to initialize the arraylist with null values then assign number values So that,
use following code that I made clear changes for you.
int dice1 = 4;
int dice2 = 3;
int dice3 = 6;
int dice4 = 4;
int dice5 = 5;
int capacity=5;
ArrayList numbers = new ArrayList(capacity);
for (int i = 0; i < capacity;i++ )
{
numbers.Add(null);
}
numbers[4] = dice5;
numbers[3] = dice4;
numbers[2] = dice3;
numbers[1] = dice2;
numbers[0] = dice1;
numbers[3] = (int.Parse(numbers[3].ToString()) * int.Parse(numbers[2].ToString()));
print(numbers[3]);

Simple cycle and wrong element

Here`s some code:
foreach (int[] temp in intList)
{
string str = GenerateGamma(0,1,10,temp);
if (str == "924890128")
answer.Add(temp);
}
Where in intList there are int arrays and each one of them has the following property: array[1] = 1(length of array is 10). Well, when I looked in answer, then I saw the array 1 4 6 0 9 3 2 7 5 8, so array[1] = 4.
Here is code of GenerateGamma().
public static string GenerateGamma(int i0, int j0, int m, int[] b)
{
Constants ct = new Constants();
int[] gamma = new int[9];
int[] inside_array = b;
string result = "";
int temp_i = i0, temp_j = j0, inttemp = 0;
for (int t = 1; t <= 9; t++)
{
temp_i = ((temp_i + 1) % m);
temp_j = ((temp_j + inside_array[temp_i]) % m);
inttemp = inside_array[temp_i];
inside_array[temp_i] = inside_array[temp_j];
inside_array[temp_j] = inttemp;
gamma[t-1] = (inside_array[(inside_array[temp_i]+inside_array[temp_j])%m]%m);
}
result = string.Join("",gamma);
return result;
}
Arrays are reference types, if you change passed array inside GenerateGamma() method the original array will be changed too.
Your array is changed because inside method you have:
int[] inside_array = b;
Here you don't create a copy of passed array, you just create copy of reference to array. So, you have one array and two references (b and inside_array) which point to the same array: b[0] = 1; and inside_array[0] = 1; do the same - they modify the same array.
If you want copy:
int[] inside_array = new int[b.Length];
for (int a = 0; a < inside_array.Length; a++)
{
inside_array[a] = b[a];
}
After this you will have two arrays and when you change one array another one won't be changed.

String to Hex int array?

Is it possible to convert a HEX string to an integer array?
// This string...
string a = "8FCC44";
// Should look like this:
int[] b = {0x8f,0xcc,0x44};
But I don't have any idea how to do this.
I found this question, but i can't understand the answer. I am new to C#, so it would be nice if anybody could give me an example.
Thanks in advance!
int[] ConvertToIntArray(string a)
{
List<int> x = new List<int>();
for(int i=0; i<a.Length-1; i+=2)
x.Add(int.Parse(a.Substring(i, 2), System.Globalization.NumberStyles.HexNumber));
return x.ToArray();
}
You can then print them as Hex or Decimal using ToString() overloads of int (Int32) class.
Another way:
var a = "8fcc44";
var b = Enumerable.Range(0, a.Length / 2).Select(x =>
Convert.ToInt32(a.Substring(x * 2, 2), 16)).ToArray();
The answer focuses on Java, but it is also possible to do this in C# in a similar way. Basicly you have to divide the string into substrings, each 2 characters long:
"8FCC44" -> "8F", "CC", "44"
You can do this using a for loop:
for (int i = 0; i < a.Length; i += 2)
The loop variable i represents the start index of the current substring, this is why it always increases by 2. We can convert each substring using Int32.Parse:
Convert.ToInt32(a.Substring(i, 2), 16);
The last parameter represents the base of the source string (HEX = base 16).
Now we need an array to store the results. The size of the array can be calculated by the length of the string, divided by the length of each substring (= 2):
int[] b = new int[a.Length / 2];
To bring it all together your code could look like this:
string a = "8FCC44";
int[] b = new int[a.Length / 2];
for (int i = 0, int j = 0; i < a.Length; i += 2, j++)
b[j] = Convert.ToInt32(a.Substring(i, 2), 16);
Hope this helps!
static void Main(string[] args)
{
string a = "8fcc44";
int itemNumber = 0;
int[] iArray = new int[3];
for (int i = 0; i < a.Length - 1; i += 2)
{
iArray[itemNumber] = (int.Parse(a.Substring(i, 2), System.Globalization.NumberStyles.HexNumber));
itemNumber++;
}
}

Categories

Resources