if/unless modifiers vs. and/or - ruby

Sometimes, you want to use an if/unless modifier but the conditionally executed part includes a local variable that is to be defined within the condition. For example,
a = [1, 2, 3]
n = 3*(x**2) + 4*x + 5 if x = a[2]
m = 6*(y**2) + 7*y + 8 unless (y = a[0]).zero?
will give a parsing error because x,y is read before the if/unless modifier. In order to avoid that, I think it is pretty much common (at least for me) to use and instead of if and or instead of unless:
x = a[2] and n = 3*(x**2) + 4*x + 5
(y = a[0]).zero? or m = 6*(y**2) + 7*y + 8
Besides the fact that it does not raise an error, is there any difference? Is there any side effects in doing this? And, is there a better way?

Alternatives that I would choose (and have used) when this issue arises:
if x=a[2]
n = 3*(x**2) + 4*x + 5
end
if x=a[2] then n = 3*(x**2) + 4*x + 5 end
x=nil
n = 3*(x**2) + 4*x + 5 if x=a[2]

the logical or returns true if one of the sides evaluates to true...
are you sure that the or and unless lines are equal
(could be, that the or line always evaluates to true since m = 6*(y**2) + 7*y + 8 is true)?
EDIT:
nope i was wrong take a look at this doc - seems to be what you are looking for

I just realized that there is a difference between
if x = something then f(x) end (1)
and
x = something and f(x) (2)
That is when something takes the value false. In this case, (1) returns nil, whereas (2) returns false.

Related

Any useful mathematical function / algorithm to break down big numbers?

So what I want to do is breaking down numbers that are dozens of thousands big into smaller numbers, preferably 2~9.
The first thing came to my mind was prime factorization, for instance the number 49392 can be expressed as (2 x 2 x 2 x 2 x 3 x 3 x 7 x 7 x 7). But there are prime numbers and numbers such as 25378 = 2 × 12689 that cant be expressed with only multiplication.
So I want to break these numbers down using multiplication and addition, for example, the number 25378 could be expressed as 25346 + 32 = (2 × 19 × 23 × 29) + (2^5). Still, 23 and 29 are too big but I just picked random number just to show what I mean by using addtion and multiplication together to express big numbers, I'm sure there's a better combination of number that express 25378 than 25346 and 32.
Anyways, I thought programming this would involve ton of unnecessary if statement and would be incredibly slow in the big picture. So I was wondering, if there is a mathematical algorithm or function that does this thing? If not, I could just optimize the code myself, but I was just curious, I couldn't find anything on google myself though.
Assuming the problem is to write a number as the simplest expression containing the numbers 1-9, addition and multiplication (simplest = smallest number of operators), then this Python program does this in O(N^2) time.
A number N can be written as the sum or product of two smaller numbers, so if you've precalculated the simplest way of constructing the numbers 1..N-1, then you can find the simplest way of constructing N in O(N) time. Then it's just a matter of avoiding duplicate work -- for example without loss of generality in the expressions A+B and AB, A<=B, and nicely printing out the final expression.
def nice_exp(x, pri):
if isinstance(x, int):
return str(x)
else:
oppri = 1 if x[0] == '*' else 0
if oppri < pri:
bracks = '()'
else:
bracks = ['', '']
return '%s%s %s %s%s' % (bracks[0], nice_exp(x[1], oppri), x[0], nice_exp(x[2], oppri), bracks[1])
def solve(N):
infinity = 1e12
size = [infinity] * (N+1)
expr = [None] * (N+1)
for i in range(N+1):
if i < 10:
size[i] = 1
expr[i] = i
continue
for j in range(2, i):
if j * j > i: break
if i%j == 0 and size[j] + size[i//j] + 1 < size[i]:
size[i] = size[j] + size[i//j] + 1
expr[i] = ('*', expr[j], expr[i//j])
for j in range(1, i):
if j > i-j: break
if size[j] + size[i-j] + 1 < size[i]:
size[i] = size[j] + size[i-j] + 1
expr[i] = ('+', expr[j], expr[i-j])
return nice_exp(expr[N], 0)
print(solve(25378))
Output:
2 * (5 + 4 * 7 * (5 + 7 * 8 * 8))

Algorithm to print all valid combations of n pairs of parenthesis

I'm working on the problem stated in the question statement. I know my solution is correct (ran the program) but I'm curious as to whether or not I'm analyzing my code (below) correctly.
def parens(num)
return ["()"] if num == 1
paren_arr = []
parens(num-1).each do |paren|
paren_arr << paren + "()" unless "()#{paren}" == "#{paren}()"
paren_arr << "()#{paren}"
paren_arr << "(#{paren})"
end
paren_arr
end
parens(3), as an example, will output the following:
["()()()", "(()())", "(())()", "()(())", "((()))"]
Here's my analysis:
Every f(n) value is roughly 3 times as many elements as f(n-1). So:
f(n) = 3 * f(n-1) = 3 * 3 * f(n-2) ~ (3^n) time cost.
By a similar analysis, the stack will be occupied by f(1)..f(n) and so the space complexity should be 3^n.
I'm not sure if this analysis for either time or space is correct. On the one hand, the stack only holds n function calls, but each of these calls returns an array ~3 times as big as the call before it. Does this factor into space cost? And is my time analysis correct?
As others have mentioned, your solution is not correct.
My favourite solution to this problem generates all the valid combinations by repeatedly incrementing the current string to the lexically next valid combination.
"Lexically next" breaks down into a few rules that make it pretty easy:
The first difference in the string changes a '(' to a ')'. Otherwise the next string would be lexically before the current one.
The first difference is as far to the right as possible. Otherwise there would be smaller increments.
The part after the first difference is lexically minimal, again because otherwise there would be smaller increments. In this case that means that all the '('s come before all the ')'.
So all you have to do is find the rightmost '(' that can be changed to a ')', flip it, and then append the correct number of '('s and ')'s.
I don't know Ruby, but in Python it looks like this:
current="(((())))"
while True:
print(current)
opens=0
closes=0
pos=0
for i in range(len(current)-1,-1,-1):
if current[i]==')':
closes+=1
else:
opens+=1
if closes > opens:
pos=i
break
if pos<1:
break
current = current[:pos]+ ")" + "("*opens + ")"*(closes-1)
Output:
(((())))
((()()))
((())())
((()))()
(()(()))
(()()())
(()())()
(())(())
(())()()
()((()))
()(()())
()(())()
()()(())
()()()()
Solutions like this turn out to be easy and fast for many types of "generate all the combinations" problems.
Recursive reasoning makes a simple solution. If the number of left parens remaining to emit is positive, emit one and recur. If the number of right parens remaining to emit is greater than the number of left, emit and recur. The base case is when all parens, both left and right, have been emitted. Print.
def parens(l, r = l, s = "")
if l > 0 then parens(l - 1, r, s + "(") end
if r > l then parens(l, r - 1, s + ")") end
if l + r == 0 then print "#{s}\n" end
end
As others have said, the Catalan numbers give the number of strings that will be printed.
While this Ruby implementation doesn't achieve it, a lower level language (like C) would make it easy to use a single string buffer: O(n) space. Due to substring copies, this one is O(n^2). But since the run time and output length are O(n!), O(n) space inefficiency doesn't mean much.
I found Tom Davis' article, "Catalan Numbers," very helpful in explaining one recursive method for defining the Catalan Numbers. I'll try to explain it myself (in part, to see how much of it I've understood) as it may be applied to finding the set of all unique arrangements of N matched parentheses (e.g., 1 (); 2 ()(), (()); etc. ).
For N > 1 let (A)B represent one arrangement of N matched parentheses, where A and B each have only balanced sets of parentheses. Then we know that if A contains k matched sets, B must have the other N - k - 1, where 0 <= k <= N - 1.
In the following example, a dot means the group has zero sets of parentheses:
C_0 => .
C_1 => (.)
To enumerate C_2, we arrange C_1 as AB in all ways and place the second parentheses around A:
. () = AB = C_0C_1 => (.)()
() . = AB = C_1C_0 => (()) .
Now for C_3, we have three partitions for N - 1, each with its own combinations: C_0C_2, C_1C_1, C_2C_0
C_0C_2 = AB = . ()() and . (()) => ()()(), ()(())
C_1C_1 = AB = ()() => (())()
C_2C_0 = AB = ()() . and (()) . => (()()), ((()))
We can code this method by keeping a set for each N and iterating over the combinations for each partition. We'll keep the individual arrangements as bits: 0 for left and 1 for right (this appears backwards when cast as a binary string).
def catalan
Enumerator.new do |y|
# the zero here represents none rather than left
s = [[0],[2]]
y << [0]
y << [2]
i = 2
while true
s[i] = []
(0..i - 1).each do |k|
as = s[k]
bs = s[i - k - 1]
as.each do |a|
bs.each do |b|
if a != 0
s[i] << ((b << (2*k + 2)) | (1 << (2*k + 1)) | (a << 1))
else
s[i] << (2 | (b << 2))
end
end # bs
end # as
end # k
y.yield(s[i])
i = i + 1
end # i
end # enumerator
end
catalan.take(4)
# => [[0], [2], [10, 12], [42, 50, 44, 52, 56]]
The yielder is lazy: although the list is infinite, we can generate as little as we like (using .take for example):
catalan.take(4).last.map{|x| x.to_s(2)}
# => ["101010", "110010", "101100", "110100", "111000"]
The former generation obliges us to keep all previous sets in order to issue the next. Alternatively, we can build a requested set through a more organic type, meandering recursion. This next version yields each arrangement to the block, so we can type:
catalan(4){
|x| (0..7).reduce(""){
|y,i| if x[i] == 0 then y + "(" else y + ")" end
}
}.take(14)
# => ["(((())))", "((()()))", "((())())", "((()))()", "(()(()))", "(()()())",
# "(()())()", "(())(())", "(())()()", "()((()))", "()(()())", "()(())()",
# "()()(())", "()()()()"]
Direct generation:
def catalan(n)
Enumerator.new do |y|
s = [[0,0,0]]
until s.empty?
left,right,result = s.pop
if left + right == 2 * n
y << yield(result)
end
if right < left
s << [left, right + 1, result | 1 << (left + right)]
end
if left < n
s << [left + 1, right, result]
end
end
end
end

Unable to understand the result of this hash function

I was reading my notes from the algorithms class (several years old) and I found this:
which says: Assuming that
h(k) = k mod m, where m = 4 and k = 100, then h(k) = 4
Is this true? I would think that 4 * 25 = 100, thus h(k) = 0. What am I missing?
I thought it was a typo, but I just checked the newest version of the notes and it's still the same!
The modulo operator can never return that result, as it represents the remainder after integer division.
So this rule holds for positive integers x and y:
x mod y = z ⇒ z < y
Another way to write the above modulo operation is:
⎣x/y⎦.y + z = x
If somehow you would achieve that z == y then obviously you did something wrong in the ⎣x/y⎦ part.

Boolean expression in SOP

I'm new to boolean expressions.
I've been given the task to simplify
F(w,x,y,z) = xy’ + x’z’ + wxz + wx’y by using K map.
I've done it and the result is wx’+w’y’+xyz.
Now I have to "Write it in a standard SOP form. You need to provide the steps through which you get the standard SOP".
And i have no idea how to do it. I thought result after k map is sop.
Yes, you already have it in SOP form. But the second question is about Standard (aka canonical) SOP form. That's much simpler to find than having to use K-maps (but it's often long), it's just the sum of minterms.
I think your solution does not cover all ones. These Karnaugh maps show the original expression, the simplified version (minimal SOP) and the canonical SOP, where every product contains all literals (all given variables or their negation).
The original expression is
F(w,x,y,z) = x·¬y + ¬x·¬z + w·x·z + w·¬x·y
– there are two fours and two pairs circled in the corresponding (first one) K-map.
The original expression simplified using K-map (shown in the second one):
F(w,x,y,z) = x·¬y + ¬x·¬z + w·y·z
is different than yours, but you can check for example with wolframalpha online tool, that it is the simplified original expression.
It is also the minimal DNF, but not a sum of minterms (where the output is equal to 1), because there are not all variables in every product of the sum.
The third K-map shows ten minterms circled. They form the canonical DNF:
F(w,x,y,z) = m0 + m2 + m4 + m5 + m8 + m10 + m11 + m12 + m13 + m15 =
= ¬w·¬x·¬y·¬z + ¬w·¬x·y·¬z + ¬w·x·¬y·¬z + ¬w·x·¬y·z + w·¬x·¬y·¬z
+ w·¬x·y·¬z + w·¬x·y·z + w·x·¬y·¬z + w·x·¬y·z + w·x·y·z
I checked your simplified expression, but there are not all ones covered (even if there were some useful do not care states (marked X)). Maybe you made a typo. Or could there be a typo in the original expression?
We can implement the K-Map algorithm in python for 4 variables, as shown below. The function accepts the Boolean function in SOP (sum of products) form and the names of the variables and returns a simplified reduced representation. Basically you need to create rectangular groups containing total terms in power of two like 8, 4, 2 and try to cover as many elements as you can in one group (we need to cover all the ones).
For example, the function can be represented F(w,x,y,z) = xy’ + x’z’ + wxz + wx’y in SOP form as f(w,x,y,z)=∑(0,2,4,5,8,10,11,12,13,15), as can be seen from the below table:
As can be seen from the output of the next code snippet, the program outputs the simplified form x¬y + ¬x¬z + wyz, where negation of a boolean variable x is represented as ¬x in the code.
from collections import defaultdict
from itertools import permutations, product
def kv_map(sop, vars):
sop = set(sop)
not_covered = sop.copy()
sop_covered = set([])
mts = [] # minterms
# check for minterms with 1 variable
all_3 = [''.join(x) for x in product('01', repeat=3)]
for i in range(4):
for v_i in [0,1]:
if len(not_covered) == 0: continue
mt = ('' if v_i else '¬') + vars[i]
s = [x[:i]+str(v_i)+x[i:] for x in all_3]
sop1 = set(map(lambda x: int(x,2), s))
if len(sop1 & sop) == 8 and len(sop_covered & sop1) < 8: # if not already covered
mts.append(mt)
sop_covered |= sop1
not_covered = not_covered - sop1
if len(not_covered) == 0:
return mts
# check for minterms with 2 variables
all_2 = [''.join(x) for x in product('01', repeat=2)]
for i in range(4):
for j in range(i+1, 4):
for v_i in [0,1]:
for v_j in [0,1]:
if len(not_covered) == 0: continue
mt = ('' if v_i else '¬') + vars[i] + ('' if v_j else '¬') + vars[j]
s = [x[:i]+str(v_i)+x[i:] for x in all_2]
s = [x[:j]+str(v_j)+x[j:] for x in s]
sop1 = set(map(lambda x: int(x,2), s))
if len(sop1 & sop) == 4 and len(sop_covered & sop1) < 4: # if not already covered
mts.append(mt)
sop_covered |= sop1
not_covered = not_covered - sop1
if len(not_covered) == 0:
return mts
# check for minterms with 3 variables similarly (code omitted)
# ... ... ...
return mts
mts = kv_map([0,2,4,5,8,10,11,12,13,15], ['w', 'x', 'y', 'z'])
mts
# ['x¬y', '¬x¬z', 'wyz']
The following animation shows how the above code (greedily) simplifies the Boolean function given in SOP form (the basic goal is to cover all the 1s with minimum number of power-2 blocks). Since the algorithm is greedy it may get stuck to some local minimum, that we need to be careful about.

Efficient polynomial evaluation with Horner's Algorithm

I have the equation y = 3(x+1)^2 + 5(x+1)^4.
Using Horner's scheme I could evaluate this polynomial in this form, y = 8+x(26+x(33+x(20+5x))), thus requiring 8 arithmetic operations.
I could also evaluate it in this form, y = (x+1)^2 * ((5x+10)x+8), requiring 7 operations.
I've been told this can be done in 5 operations but Horner's algorithm is supposed to be most efficient and it can only do it in 7 operations. Am I missing something?
Let a = (x+1)^2, that's 2 ops. Then y=3a + 5a^2 = a(3+5a), 3 more ops for a total of 5.
3(x+1)^2 + 5(x+1)^4 = (x+1)^2[3 + 5(x+1)^2].
I can do that in 5 operations:
1) x+1
2) (x+1)^2
3) 5(x+1)^2
4) 5(x+1)^2 + 3
5) (x+1)^2[5(x+1)^2 + 3]

Resources