Scilab for Cutting Stock Algorithm - optimization

I'm new to Scilab (and programming in general). I'm trying to implement a Scilab code to solve the cutting stock problem aka 'bin packing'.
The problem: given 'n' items of sizes[] (a vector from s1 to sn), and same capacity for all bins (c=1000), I need to minimize the number of bins required to fit all items.
I'm trying the 'next item algorithm', i.e., pick the first item from the vector, put it in the bin, then pick the next item and try to put in the same bin, in case there is no enough space, then create another bin.
Actually I don't need help in improving the algorithm, but rather in implement the code for this specific one.
Here is what I've tried so far:
// 'n' is the number of items to be packed
// 'c' is the capacity (how much items fit in the bin)
// 'sizes' a vector containing the size of n items
// 'nbins' number of bins used so far
// 'bin_rem' space left in current bin
sizes=[400,401,402,403,404,405,406,408,409,411,428,450,482]
c=1000
n=length(sizes)
nbins = 0
bin_rem = c
function y = bins(sizes,c,n)
for i=0; i<n; i=i+1
if sizes[i] > bin_rem
nbins=nbins+1
bin_rem = c - sizes(i)
bin_rem = bin_rem - sizes(i)
end
endfunction
disp ("Number of bins needed "+string(bins([sizes,c,n])))
end
I'm stuck with this error below and have no idea on how to solve it.
at line 20 of executed file
endfunction
^~~~~~~~~~~^
Error: syntax error, unexpected endfunction, expecting end
Any help?

First, seems like you still don't quite understand Scilab's syntax, since I see you using sizes[i], instead of sizes(i), and calling bins([sizes,c,n]). So, for now, try not to use functions. As for the error you get, it happens because you forgot one end. The way you wrote your code, only the if statement is closed, and for loop is still open.
Secondly, when you correct that, you'll notice that your program does not work properly, and that is because you defined the loop wrong. In Scilab, the for loop is actually a "for each" loop, therefore, you need to provide a full range of values for each iteration, instead of starting value (i=0), condition (i<n) and increment function (i=i+1).
Thirdly, seems like you understand the algorithm you're trying to use, but you implemented it wrong: the last line inside the loop should be the else statement.
Solving all those, you have the following piece of code:
sizes=[400,401,402,403,404,405,406,408,409,411,428,450,482]
c=1000
n=length(sizes)
nbins = 0 //should start as 0
bin_rem = 0 //should start as 0
for i = 1:n
if sizes(i) > bin_rem
nbins = nbins + 1;
bin_rem = c - sizes(i);
else
bin_rem = bin_rem - sizes(i);
end
end
disp ("Number of bins needed "+string(nbins))
Just to clarify, 1:n means a vector from 1 to n with pace of 1. You could have also written for i = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].

Related

Understanding the DFS portion of Number of Islands in Kotlin

Here's the question:
"Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's (water), return the number of islands.
An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
Input: grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
Output: 1
Example 2:
Input: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
Output: 3 "
So this was an answer I saw for the question "Number of Islands". I get most of the code except for the last part of it (the directional recursion part)
fun numIslands(grid: Array<CharArray>): Int {
var count = 0
for (i in grid.indices){
for (j in grid[0].indices){
if(grid[i][j] == '1'){
dfs(grid, i, j)
count++
}
}
}
return count
}
private fun dfs(grid: Array<CharArray>, i: Int, j: Int){
if(i < 0 || j < 0 || i >= grid.size|| j >= grid[0].size || grid[i][j] == '0'){
return
}
//directional recursion
grid[i][j] = '0'
dfs(grid, i + 1, j)
dfs(grid, i, j + 1)
dfs(grid, i - 1, j)
dfs(grid, i, j - 1)
}
My question is what is going on in that part? Is the recursive call accounting for all sides of the 2D array surrounding the given char? Or is it something else entirely? Any help is appreciated. Thank You.
The nested loops in numIslands() identify one cell from each island, and then call dfs() to remove that whole island from the grid. (So that the next land cell it finds will be a different island, and it's counting whole islands.)
dfs() works by setting the given cell to 0 (water), and then recursively looking at the four adjacent cells. (Which then go on to remove their adjacent cells, and so on, sweeping outward until it has removed the entire island.) The clever bit there is that the if stops it when it hits water (or the edge of the grid) — which means that although it will revisit cells it has already visited, by that point they'll be water, and so it'll ignore them and not keep going over the same cells endlessly.
(Whenever you write recursive code, you always need to be thinking about how it terminates — if not, there's a real risk that it won't! In this case, recursion only happens for cells that were land, and only after setting them to water. Since the number of land cells is always reducing, and since it can't go below zero, it's guaranteed to terminate after a finite number of steps.)
dfs() is not a very helpful name! If you were writing this code, I'd suggest renaming it to something more meaningful, such as removeIslandAt(). (I'd also suggest making it an extension function on Array<CharArray>.)
To understand code like this, I always find it useful to be able to see what's going on. You might write a little function to display the current state of the grid; then you could call that at the start of dfs() (along with displaying the i and j co-ordinates). That should make it much clearer how it works. (If you really wanted, you could make an animation out of it, which would be clearer still!)

Are calculations involving a large matrix using arrays in VBA faster than doing the same calculation manually in Excel?

I am trying to do calculations as part of regression model in Excel.
I need to calculate ((X^T)WX)^(-1)(X^T)WY. Where X, W, Y are matrices and ^T and ^-1 are denoting the matrix transpose and inverting operation.
Now when X, W, Y are of small dimensions I simply run my macro which calculates these values very very fast.
However sometimes I am dealing with the case when say, the dimensions of X, W, Y are 5000 X 5, 5000 X 1 and 5000 X 1 respectively, then the macro can take a lot longer to run.
I have two questions:
Would, instead of using my macro which generates the matrices on Excel sheets and then uses Excel formulas like MMULT and MINVERSE etc. to calculate the output, it be faster for larger dimension matrices if I used arrays in VBA to do all the calculations? (I am not too sure how arrays work in VBA so I don't actually know if it would do anything to excel, and hence if it would be any quicker/less computationally intensive.)
If the answer to the above question is no it would be no quicker. Then does anybody have an idea how to speed such calculations up? Or do I need to simply put up with it and wait.
Thanks for your time.
Considering that the algorithm of the code is the same, the speed ranking is the following:
Dll custom library with C#, C++, C, Java or anything similar
VBA
Excel
I have compared a VBA vs C++ function here, in the long term the result is really bad for VBA.
So, the following Fibonacci with recursion in C++:
int __stdcall FibWithRecursion(int & x)
{
int k = 0;
int p = 0;
if (x == 0)
return 0;
if (x == 1)
return 1;
k = x - 1;
p = x - 2;
return FibWithRecursion(k) + FibWithRecursion(p);
}
is exponentially better, when called in Excel, than the same complexity function in VBA:
Public Function FibWithRecursionVBA(ByRef x As Long) As Long
Dim k As Long: k = 0
Dim p As Long: p = 0
If (x = 0) Then FibWithRecursionVBA = 0: Exit Function
If (x = 1) Then FibWithRecursionVBA = 1: Exit Function
k = x - 1
p = x - 2
FibWithRecursionVBA = FibWithRecursionVBA(k) + FibWithRecursionVBA(p)
End Function
Better late than never:
I use matrices that are bigger, 3 or 4 dimensions, sized like 16k x 26 x 5.
I run through them to find data, apply one or two formulas or make combos with other matrices.
Number one, after starting the macro, open another application like notepad, you might have a nice speed increase ☺ !
Then, I guess you switched of screen updating etc, and turned of automatic calculation
As last: don't put the data in cells, not in arrays.
Just something like:
Dim Matrix1 as String ===>'put it in declarations if you want to use it in other macros as well. Remember you can not do "blabla=activecell.value2" etc anymore!!
In the "Sub()" code, use ReDim Matrix1(1 to a_value, 1 to 2nd_value, ... , 1 to last_value)
Matrix1(45,32,63)="what you want to put there"
After running, just drop the
Matrix1(1 to a_value, 1 to 2nd_value,1) at 1st sheet,
Matrix1(1 to a_value, 1 to 2nd_value,2) at 2nd sheet, etc
Switch on screen updating again, etc
In this way my calculation went from 45 minutes to just one, by avoiding the intermediary screen update
Success, I hope it is useful for somebody

SPSS: DO REPEAT with different numbers of matched variables

I have a dataset where each case has the following set of variables:
VarA1.1 to VarA25.185 (total of 4625 variables)
VarB.1 to VarB.185 (total of 185 variables)
For each case, VarA1.1, VarA2.1, VarA3.1, etc. are all linked to the same VarB.1.
I want to use a DO REPEAT function to search through each .1 instance using both VarA and VarB.
Example code:
DO REPEAT VarA = VarA1.1 to VarA25.185
/ VarB = VarB.1 to VarB.185.
if (VarA = X) AND ((VarB-Y)<0)
VarC = Z.
END REPEAT.
EXE.
However, it seems that because there are different numbers of variables in the repeat list of VarA and VarB, they don't pair up. I want to associate each VarA#(1-25).1 with VarB.1, each VarA#(1-25).2 with each VarB.2, etc. up to VarB.185 so that in the repeat function the correct pairing of variables is used.
Thanks!
Another way to do this is to use a LOOP on the outside and a DO REPEAT on the inside. So here is some example data, with just three A variables that go to 1 to 10.
SET SEED 10.
INPUT PROGRAM.
LOOP Id = 1 TO 100.
END CASE.
END LOOP.
END FILE.
END INPUT PROGRAM.
DATASET NAME Sim.
*Making random data.
VECTOR A1.(10).
VECTOR A2.(10).
VECTOR A3.(10).
VECTOR B.(10).
NUMERIC X Y.
DO REPEAT a = A1.1 TO Y.
COMPUTE a = RV.BERNOULLI(0.5).
END REPEAT.
EXECUTE.
So here is the part you want to pay attention to. Your DO REPEAT currently loops over the 25 variables. This switches it though, so the LOOP part goes over the 25 variables, but the DO REPEAT goes over each of your A vectors.
VECTOR A1 = A1.1 TO A1.10.
VECTOR A2 = A2.1 TO A2.10.
VECTOR A3 = A3.1 TO A3.10.
VECTOR B = B.1 TO B.10.
VECTOR C.(10).
LOOP #i = 1 TO 10.
DO REPEAT A = A1 A2 A3.
IF (A(#i) = X) AND (B(#i)-Y<0) C.(#i) = B(#i).
END REPEAT.
END LOOP.
EXECUTE.
Code golf it is probably not going to beat the macro approach, since you have to define all of those VECTOR statements. But I think it is a conceptually clear way to write the program.
It looks like what you are trying to do is loop over 25 variables but repeat this for 185 variables.
It would be more intutive to use SPSS Macros to achieve this. Stepping through the below will demonstrate the building blocks for solving your data problem.
DEFINE !MyMacroName ()
SET MPRINT ON.
/* Generate some example data to match desired data format*/.
set seed = 10.
input program.
loop #i = 1 to 50.
compute case = #i.
end case.
end loop.
end file.
end input program.
dataset name sim.
execute.
!do !i =1 !to 25
vector !concat('VarA',!i,'.(185, F1.0).').
do repeat v = !concat('VarA',!i,'.1') to !concat('VarA',!i,'.185').
compute v = TRUNC(RV.UNIFORM(1,6)).
end repeat.
!doend
vector VarB.(185, F1.0).
do repeat v = VarB.1 to VarB.185.
compute v = TRUNC(RV.UNIFORM(1,6)).
end repeat.
execute.
/* Solve actual problem */.
!do !i =1 !to 185
!do !j = 1 !to 25
if (!concat('VarA',!j,'.',!i) = !concat('VarB.',!i)) !concat('VarC', !j)=1.
!doend
!doend
SET MPRINT OFF.
!ENDDEFINE.
/* Run macro */.
!MyMacroName.

Using steganography to embed data in DWT subband coefficients

I have been doing more research on the topic of DWT Steganography. I have came across the code below on the web. This is the first time I have came across subbands coefficients being specified. I have an idea what the code does but I would like someone to verify it!
steg_coeffs = [4, 4.75, 5.5, 6.25, 7];
for jj=1:size(message,2)+1
if jj > size(message,2)
charbits = [0,0,0,0,0,0,0,0];
else
charbits = dec2bin(message(jj),8)';
charbits = charbits(:)'-'0';
end
for ii=1:8
bit_count = bit_count + 1;
if charbits(ii) == 1
if HH(bit_count) <= 0
HH(bit_count) = steg_coeffs(randi(numel(steg_coeffs)));
end
else
if HH(bit_count) >= 0
HH(bit_count) = -1 * steg_coeffs(randi(numel(steg_coeffs)));
end
end
end
I think the steg_coeffs are selected coeffiecnt of the HH subband, where bits will be embedded in these selected coefficients. I have googled randi and believe that it will randomise these specified coeffs on each iteration of the loop and embed in random selection coeffs. I am correct?? Thank you
Typing help randi, you find out that randi(IMAX) will return a scalar, which will be an integer uniformly distributed (based on a prng) in the range 1:IMAX. To put simply, it chooses a random integer between 1 and IMAX.
numel(matrix) returns the total number of elements in the matrix.
So, steg_coeffs(randi(numel(steg_coeffs))) chooses a random element from steg_coeffs, by choosing a random index between 1 and 5.
The embedding algorithm is implemented in the following block.
if charbits(ii) == 1
...
else
...
end
Basically, if you're embedding a 1, the HH coefficient has to be positive. If it isn't, substitute it with one from steg_coeffs. Similarly, if you're embedding a 0, the HH coefficient has to be negative. If it isn't, substitute it with the negative of one from steg_coeffs.
The idea is that when you extract the secret, all you have to check is whether the HH coefficient is positive or negative, to know whether the bit has to be 1 or 0.

Correct loop invariant?

I am trying to find the loop invariant in the following code:
Find Closest Pair Iter(A) :
# Precondition: A is a non-empty list of 2D points and len(A) > 1.
# Postcondition: Returns a pair of points which are the two closest points in A.
min = infinity
p = -1
q = -1
for i = 0,...,len(A) - 1:`=
for j = i + 1,...,len(A) - 1:
if Distance(A[i],A[j]) < min:
min = Distance(A[i],A[j])
p = i
q = j
return (A[p],A[q])
I think the loop invariant is min = Distance(A[i],A[j]) so closest point in A is A[p] and a[q] .
I'm trying to show program correctness. Here I want to prove the inner loop by letting i be some constant, then once I've proven the inner loop, replace it by it's loop invariant and prove the outer loop. By the way this is homework. Any help will be much appreciated.
I'm not sure I fully understand what you mean by replacing the inner loop by its loop invariant. A loop invariant is a condition that holds before the loop and after every iteration of the loop (including the last one).
That being said, I wouldn't like to spoil your homework, so I'll try my best to help you without giving too much of the answer away. Let me try:
There are three variables in your algorithm that hold very important values (min, p and q). You should ask yourself what is true about these values as the algorithm goes through each pair of points (A[i], A[j])?
In a simpler example: if you were designing an algorithm to sum values in a list, you would create a variable called sum before the loop and assign 0 to it. You would then sum the elements one by one through a loop, and then return the variable sum.
Since it is true that this variable holds the sum of every single element "seen" in the loop, and since after the main loop the algorithm will have "seen" every element in the list, the sum variable necessarily holds the sum of all values in the list. In this case the loop invariant would be: The sum variable holds the sum of every element "seen" so far.
Good luck with your homework!