Checking if an array is unimodal - c

An array of integers is unimodal, if:
it is strictly increasing in the beginning;
after that it is constant;
after that, it is strictly decreasing.
The first block (increasing) and the last block (decreasing) may be absent. It is allowed that both of this blocks are absent.
For example, the following three arrays are unimodal: [5, 7, 11, 11, 2, 1], [4, 4, 2], [7], but the following three are not unimodal: [5, 5, 6, 6, 1], [1, 2, 1, 2], [4, 5, 5, 6].
Write a C program that checks if an array is unimodal.
restrictions: The function should run in the order of n.
No more than n-1 comparison operations should be performed between the array elements.
Can I use 3 while loops (not nested) and check 3 parts of the array if part number1 increasing then part number 2 is constant and part3 decreasing?

While it is possible to code this in three loops for each possible stage in the unimodal curve, such a "stateful" algorithm is not particularly mathematical. Note that an equivalent stateful algorithm is possible in a single loop by retaining state in a variable rather then in the code control flow.
It is perhaps both mathematically more robust (or at least demonstrates understanding of the mathematics of such a curve), and simpler, to test for a single common-denominator - i.e. a common relationship that holds true for every point on a unimodal curve, but not for any non-unimodal curve. In that way you can perform the test arithmetically in a single loop rather then by control flow or state transition.
That single common-denominator in this case - one that mathematically defines the curve is this: The signum of the gradient of the curve is decreasing-monotonic.
Signum is a function such that signum(a) is:
0 if a == 0,
1 if a > 0,
-1 if a < 0
While decreasing-monotonic means the value either falls or remains the same, but never rises - its all down-hill or plateau.
The gradient at any point is simply d[n+1] - d[n]. So the loop subtracts one element from the other, determines the signum, and compares it with the previous signum. The curve is not unimodal if the signum increases. That is it can rise only, be flat only or fall only, or it can rise and fall, but never rise again, with any number of level plateaus.
Note that this solution will work for the mathematical definition of a unimodal curve; the definition in your question is somewhat ambiguous and does not appear to allow for multiple plateaus. That is to say it allows:
_________
/ \
/ \
/ \
but excludes for example:
___
/ \
___/ \____
/ \
I think however that the second is clearly unimodal.
From: https://en.wikipedia.org/wiki/Unimodality:
The last part being key - zeroes don't count as a sign change. Regardless of that subtlety however, it works for all your test cases.

Related

Maximum number of primitive operations occurring in a program

I am trying to count the maximum number of operations in a program, given the pseudocode. I am given the pseudocode for finding the maximum number in an array (provided in our class slides by our professor). Now I need to count maximum possible number of primitive operations (I know usually order is the only thing we need to care about, but nonetheless I want to try this out.)
Some examples of primitive operations considered are:
Evaluating an expression
Assigning a value to a variable
Indexing into an array
Calling a method
Returning from a method, etc...
Now I understand why the first line takes 2 operations, we are indexing into the array A and assigning the value to the variable currentMax, thus there are 2 operations in total being carried out in the first line. I understand that the maximum number of primitive operations (that is the worst case) is going to be 2(n-1) for the 3 lines inside the for loop, but I am having trouble with the line that is labelled as having 2n operations.
In my mind, what is happening is the first time, i=1 is getting assigned and checked against n-1, thus 2 operations, and then the only thing occurring is the checking of i each time against n-1. The incrementing is happening in line where it says {increment counter i}. We aren't assigning any value to i in the for loop line. Thus I think the for loop line should have 2 + n operations instead of 2n.
I found another slide on the internet after a bit of searching that has the same structure, but it says 2+n instead of 2n and the total number of operations is then 7n-1 instead of 8n-2. This is shown here:
Which one is the correct one here?

Hit / Miss rate counting by array caching

I'm reading Computer Systems book from Bryant & O'Hallaron, there is an exercises the solution of which seems to be incorrect. So I'd like to make it sure
given
struct point {
int x;
int y; };
struct array[32][32];
for(i = 31; i >= 0; i--) {
for(j = 31; j >= 0; j--) {
sum_x += array[j][i].x;
sum_y += array[j][i].y; }}
sizeof(int) = 4;
we have 4096 byte cache with block (line) size 32 byte.
The hit rate is asked.
My reasoning was, we have 4096/32 = 128 blocks, each block can store 4 points (2*4*4 = 32), therefore the cache can store 1/2 of the array, i.e. 512 points (total 32*32 = 1024). Since the code accesses array in column major order, access to each point is miss. So we have array[j][i].x is always miss, while array[j][i].y is hit. Finally miss rate = hit rate = 1/2.
Problem: The solution says the hit rate is 3/4 because the cache can store the whole array.
But according to my reasoning the cache can store only half points
Did I miss something?
The array's top four rows occupy a part of the cache:
|*ooooooooooooooooooooooooooooooo|
|*ooooooooooooooooooooooooooooooo|
|*ooooooooooooooooooooooooooooooo|
|*ooooooooooooooooooooooooooooooo|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|...
Above is a schematic of the array as an applied mathematician would write the array on paper. Each element consists of an (x,y) pair, a point.
The four rows labeled o in the diagram comprise 128 points, enough to fill 1024 bytes, which is only one quarter of the cache, but see: in your code, the variable i is
the major loop counter and also
the array's row index (as written on paper).
So, let's look at the diagram again. How do your nested loops step through the array as diagrammed?
Answer: apparently, your loops step rightward across the top row as diagrammed, with j (column) as the minor loop counter. However, as you have observed, the array is stored by columns. Therefore, when element [j][i] == [0][0] is loaded, an entire cache line is loaded with it. And what comprises that cache line? It's the four elements marked * in the diagram.
Therefore, while your inner loop iterates across the array's top row as diagrammed, the cache misses every time, fetching four elements each time. And then for the next three rows, it's all hits.
This isn't easy to think about. It's a fine problem, nor would I expect you to grasp my answer instantly, but if you carefully consider the sequence of loads as I have explained, it should (after a bit of pondering) begin to make sense.
With the given loop nesting, the hit rate is indeed 3/4.
FURTHER DISCUSSION
In comments, you have asked a good follow-up question:
Can you write an element (e.g. array[3][14].x) that would hit?
I can. The array[j][i] == array[10][5] would hit. (Both .x and .y would hit.)
I will explain. The array[j][i] == array[10][4] would miss, whereas array[10][5], array[10][6] and array[10][7] would eventually hit. Why eventually? This is significant. Although all four of the elements I have named are loaded by cache hardware at once, array[10][5] is not accessed by your code (that is, by the CPU) when array[10][4] is accessed. Rather, after array[10][4] is accessed, array[11][4] is next accessed by the program and CPU.
The program and CPU only get around to accessing array[10][5] rather later.
And, indeed, if you think about it, this makes sense, doesn't it, because that is part of what caches do: they load additional data now, quietly as part of a cache line, so that the CPU can quickly access the additional data later if it needs it.
APPENDIX: FORTRAN/BLAS/LAPACK MATRIX ORDERING
It is standard in numerical computing to store matrices by column rather than by row. This is called column-major storage. Unfortunately, unlike the earlier Fortran programming language, the C programming language was not originally designed for numerical computing, so, in C, to store arrays by column, one must write array[column][row] == array[j][i]—which notation of course reverses the way an applied mathematician with his or her pencil would write it.
This is an artifact of the C programming language. The artifact has no mathematical significance but, when programming in C, you must remember to type [j][i]. [Were you programming in the now mostly obsolete Fortran programming language, you would type (i, j), but this isn't Fortran.]
The reason column-major storage is standard has to do with the sequence in which the CPU performs scalar, floating-point multiplications and additions when, in mathematical/pencil terminology, a matrix [A] left-operates on a column vector x. The standard Basic Linear Algebra Subroutines (BLAS) library, used by LAPACK and others, works this way. You and I should work this way, too, not only because we are likely to need to interface with BLAS and/or LAPACK but because, numerically, it's smoother.
If you've transcribed the program correctly then you're correct, the 3/4 answer is wrong.
The 3/4 answer would be correct if the indexes in the innermost sum += ... statements were arranged so that the rightmost index varied the most quickly, i.e. as:
sum_x += array[i][j].x;
sum_y += array[i][j].y;
In that case the 1st, 5th, 9th ... iterations of the loop would miss, but the line loaded into the cache by each of those misses would cause the next three iterations to hit.
However, with the program as written, every iteration misses. Each cache line that is loaded from memory supplies data for only a single point, and then that line is always replaced before the data for any of the other three points in the line is accessed.
As an example (assuming for simplicity that the address of the first member array[0][0] is aligned with the start of the cache), the reference to array[31][31] in the first pass through the loop is a miss that causes line 127 of the cache to be loaded. Line 127 now contains the data for [31][28], [31][29], [31][30] and [31][31]. However, the fetch of array[15][31] causes line 127 to be overwritten before array[31][30] is referenced, so when [31][30]'s turn eventually arrives it is a miss too. And then a miss at [15][30] replaces the line before [31][29] is referenced.
IMO your 1/2 hit ratio is overgenerous because it counts the access to the .y coordinate as a hit. However, that's not what the original 3/4 answer does. If the fetch of the .y coordinate were counted as a hit then the original answer would have been 7/8. Instead it counts each complete point, or perhaps each loop iteration, as a hit or a miss. By that measure the hit rate for the program as written in your question is a nice round 0.

How to pick a Random Number using batch within a range

I was wondering how to use the %random% variable to pick a number within a range smaller then 0-30000 (I made a rough estimate). I read a couple of articles on this website and did not address my problem. In my program, I want to draw a random number from 0 to 5. Anyway one can do this?
Use the modulus function. It divides a number and returns the remainder. So divide by 6 and the range is 0 to 5 (6 units) if needing 1 to 6 add 1. See Set /?. The operators are C operators (https://learn.microsoft.com/en-us/cpp/c-language/c-operators).
This gives 1 to 6. Note the operator modulus % is escaped by another %.
Set /a num=%random% %% 6 + 1
echo %num%
The mod operator, %, is a relation on the set of integers that is injective (one-to-one) but not surjective (onto). It is therefore NOT a function proper because it is not bijective (both one-to-one AND onto (but we know what you mean)).
Care must be taken in the construction of the first half of your generator; the part that produces the integer to be modded. If you are modding at irregular clock intervals then the time of day down to the millisecond is just fine. But if you are modding from within a loop you must take care that you are not producing a subset of the full range that you wish to mod. That is: there are 1000 possible millisecond values in clock time. If your loop timing is regular to the extreme, you could be drawing small subset of integer values in millisecs on every call, and therefore producing the same modded values on every call, especially if you loop interval in msecs divides 1000 evenly.
You can use the rand() generator modulo 6 -- rand() % 6. This is what I do. You must however realize that rand() chooses without replacement integers in the range of 0 through 32767 using a recursive method (the next number produced depends entirely on the previous number drawn). Consider two numbers in the range, A and B. Initially, he probability that you draw A equals the probability that you will draw B equals 1/32768. Suppose on first draw you draw A, then the probability that you will draw A on the second draw is zero, and the probability that you will draw B is 1/32767.
One more thing: rand() is not a class and calls to it are GLOBALLY DEPENDENT within your program. So if you need to draw ranged random variables in different parts of your program the dependency described above with A and B still holds, even if you are calling from different classes.
Most languages provide a method of producing a REAL random number R, in the range 0.0 <= R < 1.0. These generators have no dependencies. In BASIC this method is rnd(), and you would code (rnd() * 1000) % 6, or some variation of that.
There are other homebrew methods of producing random variables. My fallback is the middle square method, which you can look-up anywhere.
Well, I have said a mouthfull and perhaps it seems like I am driving thumbtacks with a sledgehammer. But this information is always useful when using the built-in methods.

What is the best way to find an input for a function if you already know the output?

I'm working on a fairly complicated program here and unfortunately I've painted myself into a bit of a corner.
I have a function (let's call it f(x) for simplicity) that I know the output value of, and I need to find the input value that generates that output value (to within a certain threshold).
Unfortunately the equations behind f(x) are fairly complicated and I don't have all the information I need to simply run them in reverse- so I'm forced to perform some sort of brute force search to find the right input variable instead.
The outputs for f(x) are guaranteed to be ordered, in such a way that f(x - 1) < f(x) < f(x + 1) is always true.
What is the most efficient way to find the value of x? I'm not entirely sure if this is a "root finding" problem- it seems awfully close, but not quite. I figure there's gotta be some official name for this sort of algorithm, but I haven't been able to find anything on Google.
I'm assuming that x is an integer so the result f(x - 1) < f(x) < f(x + 1) means that the function is strictly monotonic.
I'll also assume your function is not pathological, such as
f(x) = x * cos(2 * pi * x)
which satisfies your property but has all sorts of nasties between integer values of x.
A linear bisection algorithm is appropriate and tractable here (and you could adapt it to functions which are badly behaved for non-integral x), Brent might recover the solution faster. Such algorithms may well return you a non-integral value of x, but you can always check the integers either side of that, and return the best one (that will work if the function is monotonic in all real values of x). Furthermore, if you have an analytic first derivative of f(x), then an adaption of Newton Raphson might work well, constraining x to be integral (which might not make much sense, depending on your function; it would be disastrous to apply it to the pathological example above!). Newton Raphson is cute since you only need one starting point, unlike Linear Bisection and Brent which both require the root to be bracketed.
Do Google the terms that I've italicised.
Reference: Brent's Method - Wikipedia
For a general function, I would do the following:
Evaluate at 0 and determine if x is positive or negative.
(Assuming positive) . . . Evaluate powers of 2 until you bound the value (1, 2, 4, 8, . . . )
Once you have bounds then do repeated bisection until you get the precision you are looking for
If this is being called multiple times, I would cache the values along the way to reduce the time needed for subsequent operations.

What does "loops must be folded to ensure termination" mean?

I came across "loops must be folded to enusre termination" in a paper on formal methods (abstract interpretation to be precise). I am clear on what termination means, but I do not know what a folded loop is, nor how to perform folding on a loop.
Could someone please explain to me what a folded loop is please? And if it is not implicit in, or does not follow immediately for the definition of a folded loop, how this ensures termination?
Thanks
Folding a loop is the opposite action from the better-known loop unfolding, which itself is better known as loop unrolling. Given a loop, to unfold it means to repeat the body several times, so that the loop test is executed less often. When the number of executions of the loop in advance, the loop can be completely unfolded, leaving a simple sequence of instructions. For example, this loop
for i := 1 to 4 do
writeln(i);
can be unfolded to
writeln(1);
writeln(2);
writeln(3);
writeln(4);
See C++ loop unfolding, bounds for another example with partial unfolding.
The metaphor is that the program is folded on itself many times over; unfolding means removing some or all of these folds.
In some static analysis techniques, it is difficult to deal with loops, because finding a precondition for the entry point of the loop (i.e. finding a loop invariant) requires a fixpoint computation which is unsolvable in general. Therefore some analyses unfold loops; this requires having a reasonable bound on the number of iterations, which limits the scope of programs that can be analyzed.
In other static analysis techniques, finding a good invariant is a critical part of the analysis. It doesn't help to unfold the loop, in fact partially unfolding the loop would make the loop body larger and so would make it more difficult to determine a good invariant; and completely unfolding the loop would be impractical or impossible if the number of iterations was large or unbounded. Without seeing the paper, I find the statement a bit surprising, because the code could have been written with the unfolded form, but there can be programs that the analysis only works on in a more folded form.
I have no knowledge of abstract interpretation, so I'll take the functional programming approach to folding. :-)
In functional programming, a fold is an operation applied to a list to do something with each element, updating a value each iteration. For example, you can implement map this way (in Scheme):
(define (map1 func lst)
(fold-right (lambda (elem result)
(cons (func elem) result))
'() lst))
What that does is that it starts with an empty list (let's call that the result), and then for each element of the list, from the right-hand-side moving leftward, you call func on the element and cons its result onto the result list.
The key here, as far as termination goes, is that with a fold, the loop is guaranteed to terminate as long as the list is finite, since you're iterating to the next element of the list each time, and if the list is finite, then eventually there will be no next element.
Contrast this with a more C-style for loop, that doesn't operate on a list, but instead have the form for (init; test; update). The test is not guaranteed to ever return false, and so the loop is not guaranteed to complete.

Resources