Out of memory and overflow exceptions creating small array - c#

I am new to C# and XNA. Have just managed to write a class that generates a triangular grid.
But there is one problem. I can get maximum 27 nodes length triangle.
At 28 it throws Out of memory exception and at 31 -overFlow exception.
I don't understand how it overflows or out of memory... Tried to
calculate all those memory values but they look very tiny.
It is only array of nodes affected by variable. Node class is not very big:
float x; 4 B
float y; 4 B
float z; 4 B
int[] con; int[6] 4*6=24 B
byte pass; 1 B
Color col; 32 b= 4 B
Total: 41B
sequence sum of nodes needed to create triangle is n(n+1)/2
out of memory at 28
28*29/2=406 nodes
total memory:
41*406 = 16646 B = 16.26 kB
Overflows at 31: 496 nodes is 19.9 kB
I did read articles about "out of memory exceptions", that structures size is bigger than it seems and that out of memory happens at sizes of 500MB... there is no way my small triangle would reach such huge size.
This is my whole class:
class TriMatrix
{
int len;
int Lenght;
Node[] node;
VertexPositionColor[] vertex;
public class Node
{
public float x;
public float y;
public float z;
public int[] con;
public byte pass;
public Color col;
public Node(byte passable)
{
pass = passable;
if (pass > 0)
{ col = Color.Green; }
else
{ col = Color.DarkRed; }
x = 0;
z = 0;
con = new int[6];
}
}
public TriMatrix(int lenght)
{
len = lenght;
Lenght = 0;
byte pass;
Random rnd = new Random();
for (int i = 0; i <= len; i++)
{
Lenght += Lenght + 1;
}
node = new Node[Lenght];
int num = 0;
for (int i = 0; i < len; i++)
{
for (int j = 0; j <= i; j++)
{
if (rnd.Next(0, 5) > 0) { pass = 1; } else { pass = 0; }
node[num] = new Node(pass);
node[num].x = (float)i - (float)j / 2.0f;
node[num].y = 0;
node[num].z = (float)j * 0.6f;
if (i < len - 1) { node[num].con[0] = num + i; } else { node[num].con[0] = -1; node[num].col = Color.Violet; }
if (i < len - 1) { node[num].con[1] = num + i + 1; } else { node[num].con[1] = -1; }
if (j < i) { node[num].con[2] = num + 1; } else { node[num].con[2] = -1; node[num].col = Color.Violet; }
if (j < i) { node[num].con[3] = num - i; } else { node[num].con[3] = -1; }
if (i > 0) { node[num].con[4] = num - i - 1; } else { node[num].con[4] = -1; }
if (i > 0) { node[num].con[5] = num - 1; } else { node[num].con[5] = -1; }
if (j == 0) { node[num].col = Color.Violet; }
num++;
}
}
}
public void Draw(Effect effect, GraphicsDevice graphics)
{
VertexPositionColor[] verts = new VertexPositionColor[3];
int num = 0;
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j <= i; j++)
{
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
verts[1] = new VertexPositionColor(new Vector3(node[num + i + 1].x, node[num + i + 1].y, node[num + i + 1].z), node[num + i + 1].col);
verts[2] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
if ( j < i)
{
verts[0] = new VertexPositionColor(new Vector3(node[num].x, node[num].y, node[num].z), node[num].col);
verts[1] = new VertexPositionColor(new Vector3(node[num + i + 2].x, node[num + i + 2].y, node[num + i + 2].z), node[num + i + 2].col);
verts[2] = new VertexPositionColor(new Vector3(node[num + 1].x, node[num + 1].y, node[num + 1].z), node[num + 1].col);
graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, verts, 0, 1);
}
}
num++;
}
}
}
}// endclass

I assume that your bug lies in this loop (taking the liberty to correct your spelling):
for (int i = 0; i <= len; i++)
{
Length += Length + 1;
}
Within the loop, you are incrementing the value of Length by itself plus one. This effectively means that you are doubling the value of Length for each iteration, resulting in exponential growth.
During the first few iterations, the values of Length will be: 1, 3, 7, 15, 31, 63, …. We can generalize this sequence such that, at iteration i, the value of Length will be 2i+1−1. At iteration 28, this would be 536,870,911. At iteration 31, this would be 4,294,967,295.
Edit: As you mentioned in the comment below, the correct fix for computing the number of elements in a triangular grid of length len would be:
for (int i = 1; i <= len; i++)
{
Length += i;
}
This is equivalent to the summation 1 + 2 + 3 + … + len, which computes what is known as the triangular number. It may be succinctly computed using the formula:
Length = len * (len + 1) / 2;
The reason that this number grows so large is that it is a square relation; for a side of length n, you need an area of approximately half of n².

Related

inaccurate results with function to add an array of digits together

so i have this function:
static int[] AddArrays(int[] a, int[] b)
{
int length1 = a.Length;
int length2 = b.Length;
int carry = 0;
int max_length = Math.Max(length1, length2) + 1;
int[] minimum_arr = new int[max_length - length1].Concat(a).ToArray();
int[] maximum_arr = new int[max_length - length2].Concat(b).ToArray();
int[] new_arr = new int[max_length];
for (int i = max_length - 1; i >= 0; i--)
{
int first_digit = maximum_arr[i];
int second_digit = i - (max_length - minimum_arr.Length) >= 0 ? minimum_arr[i - (max_length - minimum_arr.Length)] : 0;
if (second_digit + first_digit + carry > 9)
{
new_arr[i] = (second_digit + first_digit + carry) % 10;
carry = 1;
}
else
{
new_arr[i] = second_digit + first_digit + carry;
carry = 0;
}
}
if (carry == 1)
{
int[] result = new int[max_length + 1];
result[0] = 1;
Array.Copy(new_arr, 0, result, 1, max_length);
return result;
}
else
{
return new_arr;
}
}
it basically takes 2 lists of digits and adds them together. the point of this is that each array of digits represent a number that is bigger then the integer limits. now this function is close to working the results get innacurate at certein places and i honestly have no idea why. for example if the function is given these inputs:
"1481298410984109284109481491284901249018490849081048914820948019" and
"3475893498573573849739857349873498739487598" (both of these are being turned into a array of integers before being sent to the function)
the expected output is:
1,481,298,410,984,109,284,112,957,384,783,474,822,868,230,706,430,922,413,560,435,617
and what i get is:
1,481,298,410,984,109,284,457,070,841,142,258,634,158,894,233,092,241,356,043,561,7
i would very much appreciate some help with this ive been trying to figure it out for hours and i cant seem to get it to work perfectly.
I suggest Reverse arrays a and b and use good old school algorithm:
static int[] AddArrays(int[] a, int[] b) {
Array.Reverse(a);
Array.Reverse(b);
int[] result = new int[Math.Max(a.Length, b.Length) + 1];
int carry = 0;
int value = 0;
for (int i = 0; i < Math.Max(a.Length, b.Length); ++i) {
value = (i < a.Length ? a[i] : 0) + (i < b.Length ? b[i] : 0) + carry;
result[i] = value % 10;
carry = value / 10;
}
if (carry > 0)
result[result.Length - 1] = carry;
else
Array.Resize(ref result, result.Length - 1);
// Let's restore a and b
Array.Reverse(a);
Array.Reverse(b);
Array.Reverse(result);
return result;
}
Demo:
string a = "1481298410984109284109481491284901249018490849081048914820948019";
string b = "3475893498573573849739857349873498739487598";
string c = string.Concat(AddArrays(
a.Select(d => d - '0').ToArray(),
b.Select(d => d - '0').ToArray()));
Console.Write(c);
Output:
1481298410984109284112957384783474822868230706430922413560435617

Is there a way to increase the maximum number of stack frames in Visual Studio (or avoid exceeding it otherwise)?

I am applying the so-called Wolff algorithm to simulate a very large square lattice Ising model at critical temperature in Visual Studio C#. I start out with all lattice sites randomly filled with either -1 or +1, and then the Wolff algorithm is applied for a certain number of times. Basically, per application, it randomly activates one lattice site and it checks if neighbouring lattice sites are of the same spin (the same value as the initially selected site) and with a certain chance it gets activated as well. The process is repeated for every new activation, so the activated lattice sites form a connected subset of the full lattice. All activated spins flip (*= -1). This is done a large number of times.
This is the class I use:
class WolffAlgorithm
{
public sbyte[,] Data;
public int DimX;
public int DimY;
public double ExpMin2BetaJ;
private sbyte[,] transl = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
public WolffAlgorithm(sbyte[,] data, double beta, double j)
{
Data = data;
DimX = data.GetLength(0);
DimY = data.GetLength(1);
ExpMin2BetaJ = Math.Exp(- 2 * beta * j);
}
public void Run(int n, int print_n)
{
Random random = new Random();
DateTime t0 = DateTime.Now;
int act = 0;
for (int i = 0; i < n; i++)
{
int x = random.Next(0, DimX);
int y = random.Next(0, DimY);
int[] pos = { x, y };
List<int[]> activations = new List<int[]>();
activations.Add(pos);
sbyte up_down = Data[x, y];
Data[x, y] *= -1;
CheckActivation(random, up_down, activations, x, y);
act += activations.Count;
if ((i + 1) % print_n == 0)
{
DateTime t1 = DateTime.Now;
Console.WriteLine("n: " + i + ", act: " + act + ", time: " + (t1 - t0).TotalSeconds + " sec");
t0 = t1;
act = 0;
}
}
}
private void CheckActivation(Random random, sbyte up_down, List<int[]> activations, int x, int y)
{
for (int i = 0; i < transl.GetLength(0); i++)
{
int tr_x = (x + transl[i, 0]) % DimX;
if (tr_x < 0) tr_x += DimX;
int tr_y = (y + transl[i, 1]) % DimY;
if (tr_y < 0) tr_y += DimY;
if (Data[tr_x, tr_y] != up_down)
{
continue;
}
if (random.NextDouble() < 1 - ExpMin2BetaJ)
{
int[] new_activation = { tr_x, tr_y };
activations.Add(new_activation);
Data[tr_x, tr_y] *= -1;
CheckActivation(random, up_down, activations, tr_x, tr_y);
}
}
}
}
When I approach the equilibrium configuration, the activated groups become so large, that the recursive function exceeds the maximum number of stack frames (apparently 5000), triggering the StackOverflowException (fitting for my first post on StackOverflow.com, I guess haha).
What I've tried:
I have tried adjusting the maximum number of stack frames like what is proposed here: https://www.poppastring.com/blog/adjusting-stackframes-in-visual-studio
This did not work for me.
I have also tried to reduce the number of stack frames needed by just copying the same function in the function (however ugly this looks):
private void CheckActivation2(Random random, sbyte up_down, List<int[]> activations, int x, int y)
{
for (int i = 0; i < transl.GetLength(0); i++)
{
int tr_x = (x + transl[i, 0]) % DimX;
if (tr_x < 0) tr_x += DimX;
int tr_y = (y + transl[i, 1]) % DimY;
if (tr_y < 0) tr_y += DimY;
if (Data[tr_x, tr_y] != up_down)
{
continue;
}
if (random.NextDouble() < 1 - ExpMin2BetaJ)
{
int[] new_activation = { tr_x, tr_y };
activations.Add(new_activation);
Data[tr_x, tr_y] *= -1;
for (int i2 = 0; i2 < transl.GetLength(0); i2++)
{
int tr_x2 = (tr_x + transl[i2, 0]) % DimX;
if (tr_x2 < 0) tr_x2 += DimX;
int tr_y2 = (tr_y + transl[i2, 1]) % DimY;
if (tr_y2 < 0) tr_y2 += DimY;
if (Data[tr_x2, tr_y2] != up_down)
{
continue;
}
if (random.NextDouble() < 1 - ExpMin2BetaJ)
{
int[] new_activation2 = { tr_x2, tr_y2 };
activations.Add(new_activation2);
Data[tr_x2, tr_y2] *= -1;
CheckActivation2(random, up_down, activations, tr_x2, tr_y2);
}
}
}
}
}
This works, but it is not enough and I don't know how to scale this elegantly by an arbitrary number of times, without calling the function recursively.
I hope anyone can help me with this!

Bubble sort 2D string array

How can I bubble sort a 2D string array by their lenght? In the array's zeroth column there are random generated messages and in the first column there are random generated priorities.
string[,] array = new string[50, 2];
Random r = new Random();
int number = 0;
int space = 0;
double fontossag = 0;
for (int i = 0; i < 50; i++)
{
string message = "";
int hossz = r.Next(10,51);
for (int h = 0; h < hossz; h++)
{
number = r.Next(0,101);
space = r.Next(0, 101);
if (number<=50)
{
message += (char)r.Next(97,122);
}
else if(number >= 50)
{
message += (char)r.Next(65, 90);
}
if (space<=10)
{
message += " ";
}
}
for (int f = 0; f < 50; f++)
{
fontossag = r.NextDouble() * (10.0);
}
array[i, 0] += message;
array[i, 1] += fontossag;
}
I want to sort the array by the random generated messages length.
This is my method to Bubble sort on the first column length:
public static string[,] BubbleSortStringByLength(string[,] array)
{
int num = array.GetLength(0);
for (int i = 0; i < num - 1; i++)
{
for (int j = 0; j < num - i - 1; j++)
{
if (array[j, 0].Length > array[j + 1, 0].Length)
{
// swap first column
string tmp = array[j, 0];
array[j, 0] = array[j + 1, 0];
array[j + 1, 0] = tmp;
// swap second column
tmp = array[j, 1];
array[j, 1] = array[j + 1, 1];
array[j + 1, 1] = tmp;
}
}
}
return array;
}
You can download the Visual Studio solution on GitHub
So you want to compare lengths of 1st columns and swap rows to ensure descending priority:
for (bool hasWork = true; hasWork;) {
hasWork = false;
for (int row = 0; row < array.GetLength(0) - 1; ++row) {
int priority1 = array[row, 0]?.Length ?? -1;
int priority2 = array[row + 1, 0]?.Length ?? -1;
// if we have wrong order...
if (priority1 < priority2) {
// we should keep on working to sort the array
hasWork = true;
// and swap incorrect rows
for (int column = 0; column < array.GetLength(1); ++column)
(array[row, column], array[row + 1, column]) =
(array[row + 1, column], array[row, column]);
}
}
}
Please, fiddle yourself

Initialize an object after it is referenced by an other

I've got a 2 Dimensional array, which stores fields of a chessboard..
private field[,] board = new field[boardsize,boardsize];
..now when I initialize them I want to reference to the neighbours of every field, which are partly not initilized yet.
At the moment a use a work-around like this:
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
board[x,y] = new field();
}
}
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
board[x,y].setNeighbours(x, y, board);
}
}
This works fine but I'm interested if its possible to set the neighbours before or at time of the initialisation.
setNeighbour - Method:
setNeighbour(int x, int y, field[,])
{
if(field[x-1,y] != null)
this.neighbour[0] = field[x-1,y];
if(field[x-1,y+1] != null)
this.neighbour[0] = field[x-1,y+1];
if(field[x,y+1] != null)
this.neighbour[0] = field[x,y+1];
if(field[x+1,y+1] != null)
this.neighbour[0] = field[x+1,y+1];
if(field[x+1,y] != null)
this.neighbour[0] = field[x+1,y];
if(field[x+1,y-1] != null)
this.neighbour[0] = field[x+1,y-1];
if(field[x,y-1] != null)
this.neighbour[0] = field[x,y-1];
if(field[x-1,y-1] != null)
this.neighbour[0] = field[x-1,y-1];
}
You could do this:
private field[,] board = new field[boardsize,boardsize];
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
if(board[x,y] == null)
board[x,y] = new field();
board[x,y].setNeighbours(x, y, board);
}
}
and check initialization of the neighbour in the setNeighbours() method the same way:
private void setNeighbours(int x, int y, field[,] board)
{
//Initialize neighbour if not already initialized
if(board[x+1,y] == null)
board[x+1,y] = new field();
//DO SOMETHING...
}
I don't Believe it's possible to reference the neighbours since they aren't created yet. You could however add the board as a parameter to the constructor of field and use a property to look up the neighbours when needed later.
This is a classical problem... Sadly C# doesn't have continuations... They can be simulated (very slowly) through the use of Threads... Yes, it is overkill, and it is only an exercise in programming:
public sealed class WaitForReady<T> : IDisposable
{
public readonly ManualResetEvent mre = new ManualResetEvent(false);
public T Value
{
get
{
mre.WaitOne();
return this.value;
}
set
{
this.value = value;
mre.Set();
}
}
private T value;
#region IDisposable Members
public void Dispose()
{
mre.Dispose();
}
#endregion
}
public class Field
{
public Field[] Neighbours;
public Field(WaitForReady<Field> me, WaitForReady<Field>[] neighbours)
{
me.Value = this;
Neighbours = new Field[neighbours.Length];
for (int i = 0; i < neighbours.Length; i++)
{
Neighbours[i] = neighbours[i] != null ? neighbours[i].Value : null;
}
}
}
public static void Main(string[] args)
{
int boardsize = 8;
Field[,] board = new Field[boardsize, boardsize];
WaitForReady<Field>[,] boardTemp = null;
try
{
boardTemp = new WaitForReady<Field>[boardsize, boardsize];
var threads = new Thread[boardsize * boardsize];
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
boardTemp[i, j] = new WaitForReady<Field>();
}
}
int k = 0;
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
var neighbours = new WaitForReady<Field>[8];
neighbours[0] = i > 0 && j > 0 ? boardTemp[i - 1, j - 1] : null;
neighbours[1] = i > 0 ? boardTemp[i - 1, j] : null;
neighbours[2] = i > 0 && j + 1 < boardsize ? boardTemp[i - 1, j + 1] : null;
neighbours[3] = j > 0 ? boardTemp[i, j - 1] : null;
neighbours[4] = j + 1 < boardsize ? boardTemp[i, j + 1] : null;
neighbours[5] = i + 1 < boardsize && j > 0 ? boardTemp[i + 1, j - 1] : null;
neighbours[6] = i + 1 < boardsize ? boardTemp[i + 1, j] : null;
neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? boardTemp[i + 1, j + 1] : null;
int i1 = i, j1 = j;
threads[k] = new Thread(() => board[i1, j1] = new Field(boardTemp[i1, j1], neighbours));
threads[k].Start();
k++;
}
}
// Wait for all the threads
for (int i = 0; i < threads.Length; i++)
{
threads[i].Join();
}
}
finally
{
// Dispose the WaitForReady
if (boardTemp != null)
{
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
if (boardTemp[i, j] != null)
{
boardTemp[i, j].Dispose();
}
}
}
}
}
}
The "trick" here is to create the Fields in 64 separate threads. When initialized first a Field "announce" itself to everyone (by setting its corresponding WaitForReady<> object), then it asks its neighbours for their this reference. It does this through the WaitForReady<> objects it receives as a parameters. The WaitForReady<> is a "special" container that can contain a single value (Value). If Value isn't set, then asking for it will put the thread in wait, until someone sets the value through the set.
For small sizes it is possible to build everything using recursion to simulate continuations. For a board size of 64 it is normally possible. This is faster.
public class Field
{
public Field[] Neighbours;
public Field(int i, int j, int boardsize, Func<Field>[,] getters)
{
Console.WriteLine("Building [{0},{1}]", i, j);
getters[i, j] = () => this;
Neighbours = new Field[8];
Neighbours[0] = i > 0 && j > 0 ? getters[i - 1, j - 1]() : null;
Neighbours[1] = i > 0 ? getters[i - 1, j]() : null;
Neighbours[2] = i > 0 && j + 1 < boardsize ? getters[i - 1, j + 1]() : null;
Neighbours[3] = j > 0 ? getters[i, j - 1]() : null;
Neighbours[4] = j + 1 < boardsize ? getters[i, j + 1]() : null;
Neighbours[5] = i + 1 < boardsize && j > 0 ? getters[i + 1, j - 1]() : null;
Neighbours[6] = i + 1 < boardsize ? getters[i + 1, j]() : null;
Neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? getters[i + 1, j + 1]() : null;
Console.WriteLine("Builded [{0},{1}]", i, j);
}
}
public static void Main(string[] args)
{
int boardsize = 8;
Field[,] board = new Field[boardsize, boardsize];
Func<Field>[,] getters = new Func<Field>[boardsize, boardsize];
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
int i1 = i, j1 = j;
getters[i, j] = () => board[i1, j1] = new Field(i1, j1, boardsize, getters);
}
}
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
getters[i, j]();
}
}
}
Another way is to let the Fields handle creation of the other fields.
It's gonna be a lot more work to write all the code, but it should be more processor efficient.
Turns out you can't do it in the constructor because you'll get into an infinite loop of fields trying to create each other (because they can't find each other yet).
I like doing things like aggressive inlining even though it only makes a tiny difference in Release mode and actually slows the code down in Debug mode. On my machine it was about .1 sec for 10k executions. Would be interested to know if that's any faster than #xanatos's answer. It's certainly a lot more code :P
using System.Runtime.CompilerServices;
namespace Algorithms
{
public class Board
{
public Field[,] fields = new Field[8, 8];
}
public class Field
{
// Neighbor positions
// 701 +1-1 +10 +1+1
// 6 2 0-1 00 0+1
// 543 -1-1 -10, -1+1
private Field[] neighbors = new Field[8];
public void FindNeighbors(Board board, int rank, int file)
{
if (rank > 0)
{
// Not on bottom
createNeighbor(board, rank - 1, file, 4);
if (file > 0)
{
// Not in bottom-left corner, so adding it
//createNeighbor(board, rank - 1, file, 4);
createNeighbor(board, rank - 1, file - 1, 5);
createNeighbor(board, rank, file - 1, 6);
if (rank < 7)
{
// Not on top corner, so adding above and left-above
createNeighbor(board, rank + 1, file - 1, 7);
createNeighbor(board, rank + 1, file, 0);
if (file < 7)
{
// Not in any corder, adding remainder
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
createNeighbor(board, rank + 1, file + 1, 1);
}
else
{
// On the right, the only fields that haven't been added yet are on the right
}
}
else
{
// on top
if (file < 7)
{
// Not on the left, so add those fields.
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
}
else
{
// On the top-left, so nothing else to add.
}
}
}
else
{
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
if (rank < 7)
{
createNeighbor(board, rank + 1, file, 0);
createNeighbor(board, rank + 1, file + 1, 1);
}
else
{
// Top-left corner, nothing to add
}
}
}
else
{
// Bottom
createNeighbor(board, rank + 1, file, 0);
if (file > 0)
{
// Not on left
createNeighbor(board, rank, file - 1, 6);
createNeighbor(board, rank + 1, file - 1, 7);
if (file < 7)
{
// Not on the right
createNeighbor(board, rank + 1, file + 1, 1);
createNeighbor(board, rank, file + 1, 2);
}
}
else
{
// Bottom-left corner
createNeighbor(board, rank + 1, file + 1, 1);
createNeighbor(board, rank, file + 1, 2);
}
}
}
// Neighbor positions
// 701 +1-1 +10 +1+1
// 6 2 0-1 00 0+1
// 543 -1-1 -10, -1+1
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void createNeighbor(Board board, int rank, int file, int neighbor)
{
var field = board.fields[rank, file];
if (field == null)
{
field = new Field();
board.fields[rank, file] = field;
// Start looking for neighbors after their object is initialized.
field.FindNeighbors(board, rank, file);
}
// Always copy a link to the field, even if it already existed
neighbors[neighbor] = field;
}
}
}

0-1 Knapsack algorithm

Is the following 0-1 Knapsack problem solvable:
'float' positive values and
'float' weights (can be positive or negative)
'float' capacity of the knapsack > 0
I have on average < 10 items, so I'm thinking of using a brute force implementation. However, I was wondering if there is a better way of doing it.
This is a relatively simple binary program.
I'd suggest brute force with pruning. If at any time you exceed the allowable weight, you don't need to try combinations of additional items, you can discard the whole tree.
Oh wait, you have negative weights? Include all negative weights always, then proceed as above for the positive weights. Or do the negative weight items also have negative value?
Include all negative weight items with positive value. Exclude all items with positive weight and negative value.
For negative weight items with negative value, subtract their weight (increasing the knapsack capavity) and use a pseudo-item which represents not taking that item. The pseudo-item will have positive weight and value. Proceed by brute force with pruning.
class Knapsack
{
double bestValue;
bool[] bestItems;
double[] itemValues;
double[] itemWeights;
double weightLimit;
void SolveRecursive( bool[] chosen, int depth, double currentWeight, double currentValue, double remainingValue )
{
if (currentWeight > weightLimit) return;
if (currentValue + remainingValue < bestValue) return;
if (depth == chosen.Length) {
bestValue = currentValue;
System.Array.Copy(chosen, bestItems, chosen.Length);
return;
}
remainingValue -= itemValues[depth];
chosen[depth] = false;
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
chosen[depth] = true;
currentWeight += itemWeights[depth];
currentValue += itemValues[depth];
SolveRecursive(chosen, depth+1, currentWeight, currentValue, remainingValue);
}
public bool[] Solve()
{
var chosen = new bool[itemWeights.Length];
bestItems = new bool[itemWeights.Length];
bestValue = 0.0;
double totalValue = 0.0;
foreach (var v in itemValues) totalValue += v;
SolveRecursive(chosen, 0, 0.0, 0.0, totalValue);
return bestItems;
}
}
Yeah, brute force it. This is an NP-Complete problem, but that shouldn't matter because you will have less than 10 items. Brute forcing won't be problematic.
var size = 10;
var capacity = 0;
var permutations = 1024;
var repeat = 10000;
// Generate items
float[] items = new float[size];
float[] weights = new float[size];
Random rand = new Random();
for (int i = 0; i < size; i++)
{
items[i] = (float)rand.NextDouble();
weights[i] = (float)rand.NextDouble();
if (rand.Next(2) == 1)
{
weights[i] *= -1;
}
}
// solution
int bestPosition= -1;
Stopwatch sw = new Stopwatch();
sw.Start();
// for perf testing
//for (int r = 0; r < repeat; r++)
{
var bestValue = 0d;
// solve
for (int i = 0; i < permutations; i++)
{
var total = 0d;
var weight = 0d;
for (int j = 0; j < size; j++)
{
if (((i >> j) & 1) == 1)
{
total += items[j];
weight += weights[j];
}
}
if (weight <= capacity && total > bestValue)
{
bestPosition = i;
bestValue = total;
}
}
}
sw.Stop();
sw.Elapsed.ToString();
If you can only have positive values then every item with a negative weight must go in.
Then I guess you could calculate Value/Weight Ratio, and brute force the remaining combinations based on that order, once you get one that fits you can skip the rest.
The problem may be that the grading and sorting is actually more expensive than just doing all the calculations.
There will obviously be a different breakeven point based on the size and distribution of the set.
public class KnapSackSolver {
public static void main(String[] args) {
int N = Integer.parseInt(args[0]); // number of items
int W = Integer.parseInt(args[1]); // maximum weight of knapsack
int[] profit = new int[N + 1];
int[] weight = new int[N + 1];
// generate random instance, items 1..N
for (int n = 1; n <= N; n++) {
profit[n] = (int) (Math.random() * 1000);
weight[n] = (int) (Math.random() * W);
}
// opt[n][w] = max profit of packing items 1..n with weight limit w
// sol[n][w] = does opt solution to pack items 1..n with weight limit w
// include item n?
int[][] opt = new int[N + 1][W + 1];
boolean[][] sol = new boolean[N + 1][W + 1];
for (int n = 1; n <= N; n++) {
for (int w = 1; w <= W; w++) {
// don't take item n
int option1 = opt[n - 1][w];
// take item n
int option2 = Integer.MIN_VALUE;
if (weight[n] <= w)
option2 = profit[n] + opt[n - 1][w - weight[n]];
// select better of two options
opt[n][w] = Math.max(option1, option2);
sol[n][w] = (option2 > option1);
}
}
// determine which items to take
boolean[] take = new boolean[N + 1];
for (int n = N, w = W; n > 0; n--) {
if (sol[n][w]) {
take[n] = true;
w = w - weight[n];
} else {
take[n] = false;
}
}
// print results
System.out.println("item" + "\t" + "profit" + "\t" + "weight" + "\t"
+ "take");
for (int n = 1; n <= N; n++) {
System.out.println(n + "\t" + profit[n] + "\t" + weight[n] + "\t"
+ take[n]);
}
}
}
import java.util.*;
class Main{
static int max(inta,int b)
{
if(a>b)
return a;
else
return b;
}
public static void main(String args[])
{
int n,i,cap,j,t=2,w;
Scanner sc=new Scanner(System.in);
System.out.println("Enter the number of values ");
n=sc.nextInt();
int solution[]=new int[n];
System.out.println("Enter the capacity of the knapsack :- ");
cap=sc.nextInt();
int v[]=new int[n+1];
int wt[]=new int[n+1];
System.out.println("Enter the values ");
for(i=1;i<=n;i++)
{
v[i]=sc.nextInt();
}
System.out.println("Enter the weights ");
for(i=1;i<=n;i++)
{
wt[i]=sc.nextInt();
}
int knapsack[][]=new int[n+2][cap+1];
for(i=1;i<n+2;i++)
{
for(j=1;j<n+1;j++)
{
knapsack[i][j]=0;
}
}
/*for(i=1;i<n+2;i++)
{
for(j=wt[1]+1;j<cap+2;j++)
{
knapsack[i][j]=v[1];
}
}*/
int k;
for(i=1;i<n+1;i++)
{
for(j=1;j<cap+1;j++)
{
/*if(i==1||j==1)
{
knapsack[i][j]=0;
}*/
if(wt[i]>j)
{
knapsack[i][j]=knapsack[i-1][j];
}
else
{
knapsack[i][j]=max(knapsack[i-1][j],v[i]+knapsack[i-1][j-wt[i]]);
}
}
}
//for displaying the knapsack
for(i=0;i<n+1;i++)
{
for(j=0;j<cap+1;j++)
{
System.out.print(knapsack[i][j]+" ");
}
System.out.print("\n");
}
w=cap;k=n-1;
j=cap;
for(i=n;i>0;i--)
{
if(knapsack[i][j]!=knapsack[i-1][j])
{
j=w-wt[i];
w=j;
solution[k]=1;
System.out.println("k="+k);
k--;
}
else
{
solution[k]=0;
k--;
}
}
System.out.println("Solution for given knapsack is :- ");
for(i=0;i<n;i++)
{
System.out.print(solution[i]+", ");
}
System.out.print(" => "+knapsack[n][cap]);
}
}
This can be solved using Dynamic Programming. Below code can help you solve the 0/1 Knapsack problem using Dynamic Programming.
internal class knapsackProblem
{
private int[] weight;
private int[] profit;
private int capacity;
private int itemCount;
private int[,] data;
internal void GetMaxProfit()
{
ItemDetails();
data = new int[itemCount, capacity + 1];
for (int i = 1; i < itemCount; i++)
{
for (int j = 1; j < capacity + 1; j++)
{
int q = j - weight[i] >= 0 ? data[i - 1, j - weight[i]] + profit[i] : 0;
if (data[i - 1, j] > q)
{
data[i, j] = data[i - 1, j];
}
else
{
data[i, j] = q;
}
}
}
Console.WriteLine($"\nMax profit can be made : {data[itemCount-1, capacity]}");
IncludedItems();
}
private void ItemDetails()
{
Console.Write("\nEnter the count of items to be inserted : ");
itemCount = Convert.ToInt32(Console.ReadLine()) + 1;
Console.WriteLine();
weight = new int[itemCount];
profit = new int[itemCount];
for (int i = 1; i < itemCount; i++)
{
Console.Write($"Enter weight of item {i} : ");
weight[i] = Convert.ToInt32(Console.ReadLine());
Console.Write($"Enter the profit on the item {i} : ");
profit[i] = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
}
Console.Write("\nEnter the capacity of the knapsack : ");
capacity = Convert.ToInt32(Console.ReadLine());
}
private void IncludedItems()
{
int i = itemCount - 1;
int j = capacity;
while(i > 0)
{
if(data[i, j] == data[i - 1, j])
{
Console.WriteLine($"Item {i} : Not included");
i--;
}
else
{
Console.WriteLine($"Item {i} : Included");
j = j - weight[i];
i--;
}
}
}
}

Categories