Evaluate combination to tackle recursively (+ 1 2) - scheme

I am reading SICP's first chapter
1.1.3 Evaluating Combinations
It states that
To evaluate a combination, do the following:
1. Evaluate the subexpressions of the combination.
2. Apply the procedure that is the value of the leftmost subexpression (the operator) to the arguments that are the values of the other subexpressions (the operands).
Suppose an combination (+ 1 2)
According to the above algorithms,
The first is to evaluate (retrieve) + 1 and 2)
The second is to apply + to 1 (store the intermediate state)
The third is to evaluate(retrieve) the intermediate state and 2 again.
The forth is to apply the intermediate state to 2.
Is it right?
What' the intermediate state of +1?

The expression (+ 1 2) is a combination composed by the primitive expressions: +, 1, and 2.
The first step says to evaluate all the subexpressions. In this case they are, respectively, the operator which performs the sum of numbers, and the numbers corresponding to the numerals 1 and 2, respectively.
So you have an operator, and two numeric values. The second step says that you must apply the operator (leftmost value) to the two numbers: in other words you must apply the sum operator to 1 and 2, so to obtain the number 3. And the process terminate.
Note that there are no intermediate states in this computation.

The second is to apply + to 1
No, the second step is to call the function + with the argument values of 1 and 2.
This then computes the sum of 1 and 2 and returns 3.

Related

Write {(+/3<?⍵⍴6)×100÷⍵}1000 tacitly

Inspired by some Conor Hoekstra YouTube videos, I tried doing some baby steps in APL and also convert my small lines to point-free style. But for this (percentage of rolls of 4, 5, or 6 in 1000 die-6 rolls) I can't wrap my head around how to eliminate the omega before the reshape.
{(+/3<?⍵⍴6)×100÷⍵}1000
Let's take it step by step:
{(+/3<?⍵⍴6)×100÷⍵}
First we need to express every part of the function that uses the argument, as a function of the argument. The multiplication combines the two main parts:
{+/3<?⍵⍴6}×{100÷⍵}
In the rightmost part, {100÷⍵}, we need the argument. There are a couple of ways we can deal with this:
We can use an identity function ⊢ to represent it: 100÷⊢
We can bind (a.k.a. curry) the left argument, 100, to the function ÷ yielding a monadic function: 100∘÷
Let's take the last approach:
{+/3<?⍵⍴6}×100∘÷
In the left part, {+/3<?⍵⍴6}, we can do the same, but need to watch out for two things, and each can be dealt with in a few different ways:
We have a constant, 6, as the rightmost part of our function.
We can change the constant into a constant function: 6⍨
We can commute (a.k.a. swap or switch) the arguments of ⍴ and use an identity function: 6⍴⍨⊢
We can bind the right argument, 6, to the function ⍴ yielding a monadic function: ⍴∘6
We have a monadic function, ?, in the middle.
We can compose ? atop ⍴: ?⍤⍴
We can compose ? beside <: <∘?
Let's take the last approach for each problem:
(+/3<∘?⍴∘6)×100∘÷
This is a fully tacit equivalent to the monadic function {(+/3<?⍵⍴6)×100÷⍵}. However, there's one more trick we can use to eliminate the parenthesis. Since × is commutative, we can swap its arguments to put the more involved expression on the right:
100∘÷×(+/3<∘?⍴∘6)
However, now we have the problem of the monadic +/ in the middle. Observe that < sees a vector on the right and a scalar on the left. In the case of F/s G v for scalar functions F and G with scalar s and vector v the inner product s F.G v is equivalent, so we can combine the summation with the comparison as follows:
100∘÷×3+.<∘?⍴∘6
Alternatively, we can observer that summation is equivalent to evaluation in base 1 because the place values in base 1 are (…,12, 11, 10) = (…, 1, 1, 1) so if we have the list (…, c, b, a) and evaluate it as a number in base 1, we get:
(… + c×12 + b×11 + a×10) =
(… + c×1 + b×1 + a×10) =
(… + c + b×1 + a×1) =
(… + c + b + a)
That is, the sum of our list. We can write this as:
100∘÷×1⊥3<∘?⍴∘6

Replace two elements with their absolute difference and generate the minimum possible element in array

I have an array of size n and I can apply any number of operations(zero included) on it. In an operation, I can take any two elements and replace them with the absolute difference of the two elements. We have to find the minimum possible element that can be generated using the operation. (n<1000)
Here's an example of how operation works. Let the array be [1,3,4]. Applying operation on 1,3 gives [2,4] as the new array.
Ex: 2 6 11 3 => ans = 0
This is because 11-6 = 5 and 5-3 = 2 and 2-2 = 0
Ex: 20 6 4 => ans = 2
Ex: 2 6 10 14 => ans = 0
Ex: 2 6 10 => ans = 2
Can anyone tell me how can I approach this problem?
Edit:
We can use recursion to generate all possible cases and pick the minimum element from them. This would have complexity of O(n^2 !).
Another approach I tried is Sorting the array and then making a recursion call where the either starting from 0 or 1, I apply the operations on all consecutive elements. This will continue till their is only one element left in the array and we can return the minimum at any point in the recursion. This will have a complexity of O(n^2) but doesn't necessarily give the right answer.
Ex: 2 6 10 15 => (4 5) & (2 4 15) => (1) & (2 15) & (2 11) => (13) & (9). The minimum of this will be 1 which is the answer.
When you choose two elements for the operation, you subtract the smaller one from the bigger one. So if you choose 1 and 7, the result is 7 - 1 = 6.
Now having 2 6 and 8 you can do:
8 - 2 -> 6 and then 6 - 6 = 0
You may also write it like this: 8 - 2 - 6 = 0
Let"s consider different operation: you can take two elements and replace them by their sum or their difference.
Even though you can obtain completely different values using the new operation, the absolute value of the element closest to 0 will be exactly the same as using the old one.
First, let's try to solve this problem using the new operations, then we'll make sure that the answer is indeed the same as using the old ones.
What you are trying to do is to choose two nonintersecting subsets of initial array, then from sum of all the elements from the first set subtract sum of all the elements from the second one. You want to find two such subsets that the result is closest possible to 0. That is an NP problem and one can efficiently solve it using pseudopolynomial algorithm similar to the knapsack problem in O(n * sum of all elements)
Each element of initial array can either belong to the positive set (set which sum you subtract from), negative set (set which sum you subtract) or none of them. In different words: each element you can either add to the result, subtract from the result or leave untouched. Let's say we already calculated all obtainable values using elements from the first one to the i-th one. Now we consider i+1-th element. We can take any of the obtainable values and increase it or decrease it by the value of i+1-th element. After doing that with all the elements we get all possible values obtainable from that array. Then we choose one which is closest to 0.
Now the harder part, why is it always a correct answer?
Let's consider positive and negative sets from which we obtain minimal result. We want to achieve it using initial operations. Let's say that there are more elements in the negative set than in the positive set (otherwise swap them).
What if we have only one element in the positive set and only one element in the negative set? Then absolute value of their difference is equal to the value obtained by using our operation on it.
What if we have one element in the positive set and two in the negative one?
1) One of the negative elements is smaller than the positive element - then we just take them and use the operation on them. The result of it is a new element in the positive set. Then we have the previous case.
2) Both negative elements are smaller than the positive one. Then if we remove bigger element from the negative set we get the result closer to 0, so this case is impossible to happen.
Let's say we have n elements in the positive set and m elements in the negative set (n <= m) and we are able to obtain the absolute value of difference of their sums (let's call it x) by using some operations. Now let's add an element to the negative set. If the difference before adding new element was negative, decreasing it by any other number makes it smaller, that is farther from 0, so it is impossible. So the difference must have been positive. Then we can use our operation on x and the new element to get the result.
Now second case: let's say we have n elements in the positive set and m elements in the negative set (n < m) and we are able to obtain the absolute value of difference of their sums (again let's call it x) by using some operations. Now we add new element to the positive set. Similarly, the difference must have been negative, so x is in the negative set. Then we obtain the result by doing the operation on x and the new element.
Using induction we can prove that the answer is always correct.

Maximum sum of sequence

Suppose we have sequence of x numbers and x-1 operators (+ or -), where the order of the numbers and the operators are fixed. For example 5-2-1+3. By different parentheses you get different values. For example (5 - 2)-1+3 = 5, 5-(2-1)+3=7 and so on. I am now interested in the maximum sum and best in linear run-time/memory space.
I think that this problem can be solved with dynamic programming, but I simply don't find a meaningful variant.
What you need here is certainly a dynamic algorithm.
This would work in a recursive way, finding the maximum value that can be gotten for every range.
Algorithm:
You could separate the numbers and the operators into different lists (if the first number is positive add + to the list first).
max_sum(expression, operators):
if len(expression) == 1: return expression
max_value = -float('inf') # minus infinity
length = len(expression)
for i in range(length):
left_exp = max_sum(expression[0:i], operators[0:i])
right_exp = max_sum(expression[i:length], operators[i:length])
value = operator[i].apply(left_exp, right_exp)
if value >= max_value:
max_value = value
return max_value
The main idea of the algorithm is that it checks the maximum sums in every possible range division, goes all the way down recursively and then returns the maximum sum it got.
The pseudo-code doesn't take into account a case where you could get a maximum value by substracting the minimum value of the right expression, but with a few tweaks I think you could fix it pretty fast.
I tried to make the pseudo-code as easy to convert to code as possible out of my head, I hope this helps you.
Let an expression be a sequence of operator-number pairs: it starts with an operator followed by a number, and ends with an operator followed by a number. Your example 5-2-1+3 can be made into an expression by placing a + at the beginning: +5-2-1+3.
Let the head of an expression be its first operator-number pair, and its tail, the rest. The head of +5-2-1+3 is +5 and the tail, -2-1+3.
In this context, let parenthesizing an expression mean placing an opening parenthesis just after the first operator and a closing parenthesis at the end of the expression, like so: +(5-2-1+3). Parenthesizing an expression with a positive head doesn't do anything. Parenthesizing an expression with a negative head is equivalent to changing every sign of its tail: -(5 -2-1+3) = -5 +2+1-3.
If you want to get an extremum by parenthesizing some of its subexpressions, then you can first make some simplifications. It's easy to see that any subexpression of the form +x1+x2+...+xn won't be split: all of its elements will be used together towards the extremum. Similarly, any subexpression of the form -x1-x2-...-xn won't be split, but may be parenthesized (-(x1-x2-...-xn)). Therefore, you can first simplify any subexpression of the first form into +X, where X is the sum of its elements, and any subexpression of the second form into -x1-X, where X is the sum of its tail elements.
The resulting expression cannot have 3 consecutive - operators or 2 consecutive + operators. Now, start from the end, find the first subexpression of the form -a-b, -a+b-c, or -a+b, and compute its potential minimum and its potential maximum:
min(-a-b) = -a-b
max(-a-b) = -(a-b)
min(-a+b-c) = -(a+b)-c
max(-a+b-c) = -a+b-c if b>=c, max(-a+b-c) = -(a+b-c) if b<=c
min(-a+b) = -(a+b)
max(-a+b) = -a+b
Repeat by treating that subexpression as a single operator-number pair in the next one, albeit with two possible values (its two extrema). This way, the extrema of each subsequent subexpression is computed until you get to the main expression, of which you can simply compute the maximum. Note that the main expression may have a positive first pair, which makes it a special case, but that's easy to take into account: just add it to the maximum.

how to modify arithmetic expression for different result range

I need to modify an existing random-based arithmetic expression, to achieve a different range of resulting values.
The equation is random % 10, with a range of results from 0 to 9.
I need resulting values between 5-9.
Is there an arithmetic expression for this?
Please only propose changes to the equation.
(Editors note: This probably means to avoid coding constructs, e.g. if(...).)
You can use (random % 5) + 5
Here (random % 5) will generate a value between 0 & 4 inclusive. Then you just add 5 to the answer to get the values between 5 & 9 inclusive

How many distinct expressions are possible?

I came across the following practice problem.
You are free to put any parentheses to the expression anywhere you want and as many as you want. However it should be a valid expression after you put the parentheses. The question is how many different numbers can you make? Ex. for 1 - 2 + 3 - 4 - 5 you can get six unique values as below:
1 - 2 + 3 - 4 - 5 = -7
1 - (2 + 3) - 4 - 5 = -13
1 - (2 + 3 - 4) - 5 = -5
1 - (2 + 3 - 4 - 5) = 5
1 - 2 + 3 - (4 - 5) = 3
1 - (2 + 3) - (4 - 5) = -3
I can't seem to figure out how to have a Dynamic Programming formulation for the problem. I just started solving problems involving Dynamic Programming and can't seem to figure out how to approach this problem.
EDIT The range of numbers is 0<=N<=100 and length of expression (<=30)
Basic idea
The parentheses are basically interposed between numbers and operators, any imbalance can be fixed at the ends of the entire expression.
Possible placements of parentheses
A ( immediatetly before either operator is illegal syntax.
A ( immediately after a + is legal but pointless, since it doesn't change the order of evaluation. I'll assume we don't do this.
A ( immediately after a - is legal and important.
A ) immediately before a + is legal and important iff there was a matching ( before.
A ) immediately before a - is legal but pointless, since opening a new pair of parenthesis after the following number gives the same sign-change and more options later on, because we will have one more open pair we can close. I'll assume we don't do this either.
This means the only parentheses we actually need are opening parentheses before negative numbers and closing parentheses after positive ones. If we stick to those two, the sign the next number is multiplied with in the summation depends only on the number of open parentheses being even or odd.
This gives us the
Substructure
Parsing the state from left to right, after every number the present sub-problem can be represented as a set of pairs of
the partial sum and
the number of open parentheses.
Working out the specific example
Reading in +1:
(1, 0)
That is, there is only one solution for this sub-problem: The partial sum so far is 1 and the number of open parentheses is 0. From now on in each sub-problem I'll have one line for the pairs arising from every pair in the previous sub-problem.
Reading in -2:
(-1, 1), (-1, 0)
I.e. the partial sum is -1, but we may or may not have inserted an opening parenthesis.
Reading in +3:
(-4,1),(-4,0)
(2,0)
New in this sub-problem: We could optionally close a pair of parentheses, but only if one was open.
Reading in -4:
(0,2), (0,1)
(-8,0), (-8,1)
(-2,0), (-2,1)
Reading in -5:
(-5,2), (-5,3)
(5,1), (5,2)
(-13,0), (-13, 1)
(-3,1), (-3,2)
(-7,0), (-7,1)
(3,1), (3,2)
In the end we get the possible sums by looking only at the first element of each pair and discarding duplicates.

Resources