Curve fitting to a 3D polynomial with variable powers - c#

I have 3 data sets. 2 for polynomial itself (let's call them x and y) and 1 for the function value (it's gonna be z).
Polynomial looks something like this (assuming the power of both dimensions is 3):
z = a00 + a01*x + a02*x^2 + a03*x^3 + a10*y + a11*y*x + a12*y*x^2 ... etc
I need to be able to set the power of each dimension when preparing for approximation of values of "a".
I don't really get how CurveFitting functions work with Math.NET Numerics, but i've tried Fit.LinearMultiDim and MultipleRegression.QR. I'm having trouble with initializing the Func delegate
var zs = new double[]
{
//values here
};
var x = new double[]
{
//values here
};
var y = new double[]
{
//values here. But the amounts are equal
};
var design = Matrix<double>.Build.DenseOfRowArrays(Generate.Map2(x, y,(t, w) =>
{
var list = new List<double>(); //Can i get this working?
for (int i = 0; i <= 3; i++)
{
for (int j = 0; j <= 3; j++)
{
list.Add(Math.Pow(t, j)*Math.Pow(w, i));
}
}
return list.ToArray();
}));
double[] p = MultipleRegression.QR(design, Vector<double>.Build.Dense(zs)).ToArray();
So ideally i need to be able to compose the function with some sort of loop that accounts for the max power of both variables.
UPD: The function is always above zero on any axis

I think i got it working.
Here's the code:
List<Func<double[], double>> ps = new List<Func<double[],double>>();
for (int i = 0; i <= polynomialOrderFirstVal; i++)
{
for (int j = 0; j <= polynomialOrderSecVal; j++)
{
var orderFirst = j;
var orderSecond = i;
ps.Add(d => Math.Pow(d[0], orderFirst) * Math.Pow(d[1],orderSecond));
}
}
var psArr = ps.ToArray();
double[] coefs = Fit.LinearMultiDim(x, y, psArr);

Related

Fill 2d array with unique random numbers from 0 to 15 C#

I can't fill it with numbers to 0 - 15 then shuffle the array, so that's not the solution
I used this code in C but now in c# it doesn't work, for some reason this code let some numbers pass the do while.
Random r = new Random();
bool unique;
int rand_num;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
do
{
unique = true;
rand_num = r.Next(16);
for (int k = 0; k < 4; k++)
{
for (int l = 0; l < 4; l++)
{
if (numbers[k, j] == rand_num)
{
unique = false;
}
}
}
} while (!unique);
numbers[i, j] = rand_num;
}
}
}
If the list of possible numbers is small, as in this case, just create the full list and randomise it first, then take the items in the order they appear. In your case, you can put the randomised numbers into a queue, then dequeue as required.
var r = new Random();
var numberQueue = new Queue<int>(Enumerable.Range(0, 16).OrderBy(n => r.NextDouble()));
var numbers = new int[4, 4];
for (var i = 0; i <= numbers.GetUpperBound(0); i++)
{
for (var j = 0; j <= numbers.GetUpperBound(1); j++)
{
numbers[i, j] = numberQueue.Dequeue();
}
}
I suggest you to use the Fisher-Yates algorithm to generate your non-repeatable sequence of random numbers.
It would be very straight-forward to implement a code to fill in a 2d array with those numbers, then.
List<int> seq = Enumerable.Range(0,16).ToList();
int[,] numbers = new int[4,4];
Random r = new();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int n = r.Next(0, seq.Count);
numbers[i,j] = seq[n];
seq.RemoveAt(n);
}
}
The approach you have taken may end up in continuous looping and take lot of time to complete.
Also checking for value in 2D using nested for loop is not efficient.
You can use HashSet to keep track of unique value. Searching in HashSet is fast.
following is the code approach I suggest.
var hashSet = new HashSet<int>();
var r = new Random();
var arr = new int[4, 4];
for(var i = 0;i<4;i++)
{
for(var j = 0;j<4;j++)
{
// Generate random value between 0 and 16.
var v = r.Next(0, 16);
// Check if the hashSet has the newly generated random value.
while(hashSet.Contains(v))
{
// generate new random value if the hashSet has the earlier generated value.
v = r.Next(0, 16);
}
//Add value to the hashSet.
hashSet.Add(v);
// add value to the 2D array.
arr[i, j] = v;
}
}
I hope this will help solving your issue.
The problem with your current approach is that as you get closer to the end of the array, you have to work harder and harder to get the next random value.
Imagine you roll a die, and each time you want to get a unique value. The first time you roll, any result will be unique. The next time, you have a 1/6 chance of getting a number that has already been obtained. And then a 2/6 chance, etc. and in the end most of your rolls will be non-unique.
In your example, you have 16 places that you want to fill with numbers 0 to 15. This is not a case of randomly generating numbers, but randomly placing them. How do we do this with a deck of cards? We shufle them!
My proposal is that you fill the array with unique sequential values and then shuffle them:
Random random = new Random();
int dim1 = array.GetLength(0);
int dim2 = array.GetLength(1);
int length = dim1 * dim2;
for (int i = 0; i < length; ++i)
{
int x = i / dim1;
int y = i % dim1;
array[x, y] = i; // set the initial values for each cell
}
// shuffle the values randomly
for (int i = 0; i < length; ++i)
{
int x1 = i / dim1;
int y1 = i % dim1;
int randPos = random.Next(i, length);
int x2 = randPos / dim1;
int y2 = randPos % dim1;
int tmp = array[x1, y1];
array[x1, y1] = array[x2, y2];
array[x2, y2] = tmp;
}
The shuffle in this code is based on the shuffle found here
int[,] numbers = new int[4, 4];
Random r = new Random();
bool unique;
int rand_num;
List<int> listRandom = new List<int> { };
for ( int i = 0; i < 4; i++ )
{
for ( int j = 0; j < 4; j++ )
{
do
{
unique = false;
if (!listRandom.Contains( rand_num = r.Next( 0, 16 )))
{
listRandom.Add( rand_num );
numbers[i, j] = rand_num;
unique = true;
}
} while ( !unique );
}
}

Convert multi-dimension array to string

I have a 3 dimensional char array initialized as such:
char[,,] cube = new char[10, 10, 10];
It's completely filled and I want to convert its contents to a single string. My current method is this:
for (int z = 0; z < 10; z++) {
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 10; x++) {
build += cube[z, y, x];
}
}
}
Attempting to do build = new string(cube) gives an error:
cannot convert from 'char[*,*,*]' to 'char*'
The for loops are incredibly fast, completing in less than a millisecond on my setup (from 1500 to 4000 ticks). Wondering if a single line method exists that will accomplish the same thing that these nested for loops are doing?
EDIT:
This code will only be used once in the entire program, so I don't need something reusable.
LINQ is your friend.
A multidimensional array implements IEnumerable but sadly apparently not IEnumerable<T>. So first we need to get an IEnumerable<T> to be able to make full use of LINQ. Luckily, we know in this case, that every item in that multidimensional array is of typechar, we just need to tell that to the compiler.
Next, to create a string, there is a convenient constructor, that accepts a char[]. And getting a char[] from an IEnumerable<char> is just one ToArray() away.
Put that together and you get:
using System.Linq;
var build = new string(cube.OfType<char>().ToArray());
This is easier than you think:
public static String FlattenToString(this char[,,] array)
{
var builder = new StringBuilder();
foreach(var #char in array)
{
builder.Append(#char);
}
return builder.ToString();
}
var cube = new char[2,2,2];
cube[0,0,0] = 'a';
cube[0,0,1] = 'b';
cube[0,1,0] = 'c';
cube[0,1,1] = 'd';
cube[1,0,0] = 'e';
cube[1,0,1] = 'f';
cube[1,1,0] = 'g';
cube[1,1,1] = 'h';
Console.WriteLine(cube.FlattenToString());
Prints out abcdefgh.
string build = string.Concat(cube.Cast<char>());
Probably not needed in your case, but a much faster alternative is copying to char[] :
//var cube = new[, ,] { { { 'a', 'b' }, { 'c', 'd' } }, { { 'e', 'f' }, { 'g', 'h' } } };
char[] temp = new char[cube.Length];
Buffer.BlockCopy(cube, 0, temp, 0, temp.Length * sizeof(char));
string build = new string(temp);
char[,,] cube = new char[10, 10, 10];
for (int z = 0; z < 10; z++)
{
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
cube[z, y, x] = (char)(65+x);
}
}
}
/* Just Filling data in array*/
var s1 = cube.OfType<char>().ToList();
string s = string.Join("",s1);

Limit the array size 2D (C# UNITY)

Hello guys is it possible to limit the array size just like this example
Now i want only to show 6 of them.
What i have done so far is this
CustomClass
const int MAX = 104; // = 8 decks * 52 cards / 4cardsoneround
const int Y = 6;
int[,] arrayRoad = new int[Y, X];
public int[,] GetRoad(int x) {
arrayRoad = new int[x, 6];
return arrayRoad;
}
Now I'm displaying it on my MainClass like this
ScoreBoard bsb = new ScoreBoard();
private void Road()
{
bsb.makeRoad(history); // Road
int[,] arrayRoad = bsb.GetRoad(6); //<--- sample value 6
string s = "";
for (int y = 0; y < arrayRoad.GetLength(0); y++)
{
//just 27 for now
for (int x = 0; x < 28; x++)
{
s += string.Format("{0:D2}",arrayRoad[y, x]);
s += ".";
}
s += "\n";
}
Debug.Log(s);
}
The problem with this code is that it's giving me an Array out of index
Is this possible??
Updated
public int[,] GetRoad(int x = MAX,int y = Y) {
arrayRoad = new int[y, x];
return arrayRoad;
}
Where in my Max = 104 and Y = 6
int[,] arrayRoad = bsb.GetRoad(12,6); //12 rows and 6 in height
string s = "";
for (int y = 0; y < arrayRoad.GetLength(0); y++)
{
for (int x = 0; x < arrayRoad.GetLength(1); x++)
{
s += string.Format("{0:D2}",arrayRoad[y, x]);
s += ".";
}
s += "\n";
}
Debug.Log(s);
}
I have all this value earlier before i perform the update code
Now when i perform the updated code here's what I got
The expected result must be this
Inside of that black marker those twelve columns only must be shown because i declared on my
int[,] arrayRoad = bsb.GetRoad(12,6);
Note this:
public int[,] GetBigEyeRoad(int x) {
arrayRoad = new int[x, 6]; // <-------------
return arrayBigEyeRoad;
There you are fixing the length of the second dimension of the array to 6.
for (int x = 0; x < 28; x++)
{
s += string.Format("{0:D2}",arrayBigEyeRoad[y, x]); // <------------
There, you are trying to access indices up to 28 on the second dimension of the array. The Out of Range error comes from that.
What I did here was copy my old array to the new one just like this code below
int[,] arrayBigRoadResult = new int[6, x];
//copy manually the element references inside array
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < x; j++)
{
arrayBigRoadResult[i, j] = arrayBigRoad[i, j];
}
}
return arrayBigRoadResult;
then by calling it just like this
int[,] arrayRoad = bsb.GetRoad(12);
It would only display 12 columns and 6 rows :)

c# feed a method with x and y values from a chart (polynomial calculation)

I have got this method to get a polynomial with my desired degree:
public static double[] Polyfit(double[] x, double[] y, int degree)
{
// Vandermonde matrix
var v = new DenseMatrix(x.Length, degree + 1);
for (int i = 0; i < v.RowCount; i++)
for (int j = 0; j <= degree; j++) v[i, j] = Math.Pow(x[i], j);
var yv = new DenseVector(y).ToColumnMatrix();
QR qr = v.QR();
// Math.Net doesn't have an "economy" QR, so:
// cut R short to square upper triangle, then recompute Q
var r = qr.R.SubMatrix(0, degree + 1, 0, degree + 1);
var q = v.Multiply(r.Inverse());
var p = r.Inverse().Multiply(q.TransposeThisAndMultiply(yv));
Console.WriteLine(p.Column(0).ToString());
return p.Column(0).ToArray();
}
How can I feed the method above with values from my chart (x and y)?
chart.Series[0].Points.... ?
I think you need this:
chart1.Series[0].YValueMembers
chart1.Series[0].XValueMember
The Points property is a getter, so you cannot set a new instance of DataPointCollection to it. You should however be able to access methods on the current DataPointCollection.
You could try something along the lines of:
chart.Series[0].Points.AddXY(double, double)
You would then iterate the array(s) and set the points manually.
MSDN DataPointCollection for more information.
A working solution is:
////generate polynomial of degree 4 fiting to the points
double[] arrayX = new double[chart.Series[0].Points.Count()];
double[] arrayY = new double[chart.Series[0].Points.Count()];
double[] arrayResult = { };
for (int i = 0; i < chart.Series[0].Points.Count(); i++)
{
arrayX[i] = chart.Series[0].Points[i].XValue;
arrayY[i] = chart.Series[0].Points[i].YValues[0];
}
arrayResult = Polyfit(arrayX, arrayY, 4);
foreach (double element in arrayResult)
{
MessageBox.Show(element.ToString());
}
double functionVarE = arrayResult[0];
double functionVarD = arrayResult[1];
double functionVarC = arrayResult[2];
double functionVarB = arrayResult[3];
double functionVarA = arrayResult[4];
double equationVar = 0;
//prepare the function series in the graph
if (chart.Series.IndexOf("function") < 0)
chart.Series.Add("function");
chart.Series[2].Points.Clear();
chart.Series[2].ChartType = SeriesChartType.Line;
for (int x = -500; x < 1000; x++) //hardcoding
{
equationVar = functionVarA * (Math.Pow(x, 4)) + functionVarB * (Math.Pow(x, 3)) + functionVarC * (Math.Pow(x, 2)) + functionVarD * x + functionVarE;
chart.Series[2].Points.AddXY(Convert.ToDouble(x), equationVar);
}
This is a working solution I coded. If you see any improvement feel free to tell me!

Sort String Array using Levenstein Algorithm results

I've been working on an Access file editor in C#, and i've been trying to get a search feature added to my program. So far, I have the database file populate a 2D array, which i then use to populate a ListView box in another window. From this new window, I would like to be able to search each entry by Model Number. So far, i've managed to incorporate the Levenstein Algorithm, which seems to have much use. I can get the algorithm to assign the distance value between each entry and the search keyboard, and assign that value to another integer array. I can also sort the results in increasing order.
However, my current problem is that i'd would like to have the Model numbers sorted with the same respect to the distance values from the Levenstein Algorithm, so that the most relevant result becomes the first choice in the ListView box. Any ideas anyone??!?!
Here's what i've got so far:
private void OnSearch(object sender, System.EventArgs e)
{
string a;
string b;
int[] result = new int[1000];
int[] sorted = new int[1000];
for (int i = 0; i < rowC; i++)
{
a = PartNum[i]; // Array to search
b = SearchBox1.Text; // keyword to search with
if (GetDistance(a, b) == 0)
{
return;
}
result[i] = GetDistance(a, b); //add each distance result into array
}
int index;
int x;
for (int j = 1; j < rowC; j++) //quick insertion sort
{
index = result[j];
x = j;
while ((x > 0) && (result[x - 1] > index))
{
result[x] = result[x - 1];
x = x - 1;
}
result[x] = index;
}
}
public static int GetDistance(string s, string t)
{
if (String.IsNullOrEmpty(s) || String.IsNullOrEmpty(t))
{
MessageBox.Show("Please enter something to search!!");
return 0;
}
int n = s.Length;
int m = t.Length;
if (n == 0)
{
return m;
}
else if (m == 0)
{
return n;
}
int[] p = new int[n + 1];
int[] d = new int[n + 1];
int[] _d;
char t_j;
int cost;
for (int i = 0; i <= n; i++)
{
p[i] = i;
}
for (int j = 1; j <= m; j++)
{
t_j = t[j - 1];
d[0] = j;
for (int i = 1; i <= n; i++)
{
cost = (s[i - 1] == t_j) ? 0 : 1;
d[i] = Math.Min(Math.Min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
}
_d = p;
p = d;
d = _d;
}
return p[n];
}
Do you have LINQ available to you? If so:
var ordered = PartNum.OrderBy(x => GetDistance(x, SearchBox1.Text))
.ToList();
// Do whatever with the ordered list
Note that this has the disadvantage of not aborting early if you find an exact match, as well as not making the actual distances available - but it's not entirely clear how you're using the results anyway...
Another option would be:
var ordered = (from word in PartNum
let distance = GetDistance(word, SearchBox1.Text))
orderby distance
select new { word, distance }).ToList();
Then you've got the distance as well.
In order to sort your array by Levenstein distance you need to include the model numbers as part of your array so that, when you sort the array by Levenstein number, the model numbers will go along for the ride.
To do this, create a class representing each part:
public class Part
{
public string PartNumber;
public int LevensteinDistance;
}
and then create an array of Part:
Part[] parts;
You can then reference each element like so:
parts[n].LevensteinDistance
parts[n].PartNumber

Categories