julian way to do python's yield (and yield from) - julia

What is julian way to do yield (and yield from) as python do?
Edit: I will try to add small example in python.
Think 4x4 chess board. Find every N moves long path chess king could do. Don't waste memory -> make generator of every path.
if we sign every position with numbers:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 16
point 0 has 3 neighbors (1, 4, 5). We could find table for every neighbors for every point:
NEIG = [[1, 4, 5], [0, 2, 4, 5, 6], [1, 3, 5, 6, 7], [2, 6, 7], [0, 1, 5, 8, 9], [0, 1, 2, 4, 6, 8, 9, 10], [1, 2, 3, 5, 7, 9, 10, 11], [2, 3, 6, 10, 11], [4, 5, 9, 12, 13], [4, 5, 6, 8, 10, 12, 13, 14], [5, 6, 7, 9, 11, 13, 14, 15], [6, 7, 10, 14, 15], [8, 9, 13], [8, 9, 10, 12, 14], [9, 10, 11, 13, 15], [10, 11, 14]]
Recursive function (generator) which enlarge given path from list of points or from generator of (generator of ...) points:
def enlarge(path):
if isinstance(path, list):
for i in NEIG[path[-1]]:
if i not in path:
yield path[:] + [i]
else:
for i in path:
yield from enlarge(i)
Function (generator) which give every path with given length
def paths(length):
steps = ([i] for i in range(16)) # first steps on every point on board
for _ in range(length-1):
nsteps = enlarge(steps)
steps = nsteps
yield from steps
We could see that there is 905776 paths with length 10:
sum(1 for i in paths(10))
Out[89]: 905776
In ipython we could timeit:
%timeit sum(1 for i in paths(10))
1.21 s ± 15.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
My julia implementation is ugly and much more complicated. And it seems to be slower.

Check out ResumableFunctions.jl
from the README
using ResumableFunctions
#resumable function fibonnaci(n::Int) :: Int
a = 0
b = 1
for i in 1:n-1
#yield a
a, b = b, a+b
end
a
end
for fib in fibonnaci(10)
println(fib)
end

You can use Julia Iterators.
struct Fibonacci
last::Int64
end
function Base.iterate(fibo::Fibonacci)
return 1, (1, 1, 2) # the first output, and the next iteration state
end
function Base.iterate(fibo::Fibonacci, state)
i, a, b = state
if i ≤ fibo.last
return a, (i + 1, b, a + b) # the output, and the next iteration state
end
end
You can then use it like this:
for i in Fibonacci(10)
print(i, " ")
end
Which outputs:
1 1 2 3 5 8 13 21 34 55 89
This can result in excellent performance, but it is often a bit verbose, and it's also tricky to decide on what iteration state to use, and how to find the next element given that state. In your chess example, I would avoid this approach, but in other cases it can come in really handy.

You can use Channels:
function fibo(n)
Channel() do ch
a, b = 0, 1
for _ in 1:n
a, b = b, a + b
put!(ch, a)
end
end
end
Use it like this:
for val in fibo(10)
print(val, " ")
end
Which outputs:
1 1 2 3 5 8 13 21 34 55
To get the yield from behavior, you can just use a for loop. For example, to get the Fibonacci sequence r times:
function repeat_fibo(r, n)
Channel() do ch
for _ in 1:r
for val in fibo(n)
put!(ch, val)
end
end
end
end
For more details, see the docs.
Note that the ResumableFunctions.jl library has some benchmarks showing that their solution is significantly faster than using Channels (see #gggg's answer). Perhaps Channel performance will improve in future Julia versions.
To get better Channel performance, you should set the channel's element type and the channel's size: for example, use Channel{Int64}(100) instead of Channel().
Here's a Julia implementation of your chess problem using Channels:
NEIG = [[1, 4, 5], [0, 2, 4, 5, 6], [1, 3, 5, 6, 7], [2, 6, 7], [0, 1, 5, 8, 9],
[0, 1, 2, 4, 6, 8, 9, 10], [1, 2, 3, 5, 7, 9, 10, 11], [2, 3, 6, 10, 11],
[4, 5, 9, 12, 13], [4, 5, 6, 8, 10, 12, 13, 14],
[5, 6, 7, 9, 11, 13, 14, 15], [6, 7, 10, 14, 15], [8, 9, 13],
[8, 9, 10, 12, 14], [9, 10, 11, 13, 15], [10, 11, 14]]
function paths(start, length)
Channel{Vector{Int64}}(100) do ch
if length == 1
put!(ch, [start])
else
for path in paths(start, length - 1)
for next_step in NEIG[path[end] + 1]
next_step in path || put!(ch, [path; next_step])
end
end
end
end
end
function paths(length)
Channel{Vector{Int64}}(100) do ch
for start in 0:15
for path in paths(start, length)
put!(ch, path)
end
end
end
end
You can count all the paths of length 10 much like in Python:
sum(1 for _ in paths(10))
You can also time it:
#time sum(1 for _ in paths(10))
On my machine this takes about 4 seconds. There are probably ways to optimize this further, but this does show that Channel performance still has some room for improvement.

Related

How to Find the Widest Valley

There are list of numbers which represent size of blocks and I want to find out biggest Valley shape in the list.
Constraint is that unlike normal valley two end can be flat like in following example [5, 5] is still counts as valley end
Some examples;
[1, 5, 5, 2, 8] => [5, 5, 2, 8] widest valley [2, 6, 8, 5] => [2,6,8] widest valley [9, 8, 13, 13, 2, 2, 15, 17] => [13, 13, 2, 2, 15, 17] widest valley
It's not a homework or something but I am wondering how I can solve it in Erlang
I solved it in another language but Erlang is a bit recursive that's why I need some help
I'm no expert, but I'd solve the problem like this:
-record(valley, {from=1, to=1, deepest=1}).
widest_valley([]) ->
[];
widest_valley([H]) ->
[H];
widest_valley([H,T]) ->
[H,T];
widest_valley(L) ->
widest_valley(L, #valley{}, #valley{}, 1, 2).
widest_valley(L, _Curr, Widest, _FlatFrom, Pos) when Pos > length(L) ->
lists:sublist(L, Widest#valley.from, 1 + Widest#valley.to - Widest#valley.from);
widest_valley(L, Curr, Widest, FlatFrom, Pos) ->
Before = lists:nth(Pos - 1, L),
AtPos = lists:nth(Pos, L),
Deepest = lists:nth(Curr#valley.deepest, L),
Curr1 = if Before == Deepest ->
Curr#valley{deepest = if AtPos < Deepest ->
Pos;
true ->
Curr#valley.deepest
end};
AtPos < Before ->
#valley{from=FlatFrom, deepest=Pos};
true ->
Curr
end,
FlatFrom1 = if AtPos == Before ->
FlatFrom;
true ->
Pos
end,
Widest1 = if Pos - Curr1#valley.from > Widest#valley.to - Widest#valley.from ->
Curr1#valley{to=Pos};
true ->
Widest
end,
widest_valley(L, Curr1, Widest1, FlatFrom1, Pos + 1).

Julia idiomatic way to split vector to subvectors based on condition

Let's say I have a vector a = [1, 0, 1, 2, 3, 4, 5, 0, 5, 6, 7, 8, 0, 9, 0] and I want to split it to smaller vectors based on a condition depending on value in that array. E.g. value being zero.
Thus I want to obtain vector of following vectors
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
So far this was working for me as a naive solution, but it loses the type.
function split_by_λ(a::Vector, λ)
b = []
temp = []
for i in a
push!(temp, i)
if λ(i)
push!(b, temp)
temp = []
end
end
b
end
split_by_λ(a, isequal(0))
Then I tried to play with ranges, which feels a bit more idiomatic, and does not lose the type.
function split_by_λ(a::Vector, λ)
idx = findall(λ, a)
ranges = [(:)(i==1 ? 1 : idx[i-1]+1, idx[i]) for i in eachindex(idx)]
map(x->a[x], ranges)
end
split_by_λ(a, isequal(0))
but it still feels very cumbersome regarding it's a rather simple task.
Is there something I'm missing, some easier way?
Maybe someone has a shorter idea but here is mine:
julia> inds = vcat(0,findall(==(0),a),length(a))
julia> getindex.(Ref(a), (:).(inds[1:end-1].+1,inds[2:end]))
5-element Array{Array{Int64,1},1}:
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
[]
Or if you want to avoid copying a
julia> view.(Ref(a), (:).(inds[1:end-1].+1,inds[2:end]))
5-element Array{SubArray{Int64,1,Array{Int64,1},Tuple{UnitRange{Int64}},true},1}:
[1, 0]
[1, 2, 3, 4, 5, 0]
[5, 6, 7, 8, 0]
[9, 0]
0-element view(::Array{Int64,1}, 16:15) with eltype Int64
Pretty much the same as Przemyslaw's answer, but maybe less cryptic dense:
function split_by(λ, a::Vector)
first, last = firstindex(a), lastindex(a)
splits = [first-1; findall(λ, a); last]
s1, s2 = #view(splits[1:end-1]), #view(splits[2:end])
return [view(a, i1+1:i2) for (i1, i2) in zip(s1, s2)]
end
Also, I changed the signature to the conventional one of "functions first", which allows you to use do-blocks. Additionally, this should work with offset indexing.
One could surely get rid of the intermediate allocations, but I think that gets ugly without yield:
function split_by(λ, a::Vector)
result = Vector{typeof(view(a, 1:0))}()
l = firstindex(a)
r = firstindex(a)
while r <= lastindex(a)
if λ(a[r])
push!(result, #view(a[l:r]))
l = r + 1
end
r += 1
end
push!(result, #view(a[l:end]))
return result
end

Next number in the sequence || General approach

how can I find the next number in this sequence ,
1, 4, 7, 8, 13, 12, 9 , ?
How to check , given any sequence of numbers , feasible or not. Any general theory or approach is very much welcomed .
One method is to go to the Online Encyclopedia of Integer Sequences and enter your list of at least six or eight numbers into the box and see if that happens to be a known sequence. For your example this doesn't find a known sequence.
If that doesn't work then you can try Mathematica's FindFormula
p=FindFormula[{1, 4, 7, 8, 13, 12, 9}];
and then
p[1] returns 1, p[2] returns 4, p[3] returns 7... and p[8] returns 106, etc.
You can read the documentation on FindFormula and you can look at the formula p by using InputForm[p] where #1 represents a variable in the function p.
In general I think this is rarely going to produce the result that you are looking for.
seq = FindSequenceFunction[{1, 4, 7, 8, 13, 12, 9}, n]
(48 - 74 n - 14 n^2 + 11 n^3 - n^4)/(3 (-13 + 3 n))
Checking the 7th number
n = 7;
seq
9
The next number is a fraction, apparently
n = 8;
seq
32/11
Show[Plot[seq, {n, 1, 10}],
ListPlot[Table[seq, {n, 1, 10}]],
PlotRange -> {{0, 10}, {-20, 30}}, AxesOrigin -> {0, 0}]

How to multiply two matrices?

I have tried to write a function for multiplying two matrices. Matrices are represented by lists inside lists like that [[1, 2], [3, 4]]. Although it gives result, it is not correct.
def Matrice_multiplicator(a, z):
if len(a[0])==len(z):
m=Matrice_create(len(a))
b=0
c=0
k=1-1
while b<len(a):
for i in range(len(a[b])):
while c<len(a[0]):
k+=a[b][c]*z[c][b]
print(k)
c+=1
m[b].append(k)
b+=1
return m
else:
return "Not multiplicable"
A matrix multiplication in standard Python could look like:
def matrix_multiplication(A, B):
a = len(A)
b = len(A[0])
c = len(B[0])
if b != len(B):
print (f"Wrong combination of dimensions: {a}x{b} and {len(B)}x{c}")
else:
return [[sum([A[i][k]*B[k][j] for k in range(b)])
for j in range(c)]
for i in range(a)]
A = [[1, 2, 3],
[4, 5, 6]]
B = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]]
print(matrix_multiplication(A, B))
Result:
[[38, 44, 50, 56],
[83, 98, 113, 128]]

Swift for-in loop dictionary experiment

I'm almost a complete programming beginner and I've started to go through a Swift ebook from Apple.
The things I read are pretty clear, but once you start to experiment things get tricky :).
I'm stuck with the experiment in the Control Flow section. Here is the initial code:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
largest
And here is the task:
Add another variable to keep track of which kind of number was the
largest, as well as what that largest number was.
As I understand, they want me to add up all the values in each number kind (get a total sum for Prime, Fibonacci and Square) and then compare the result to show the largest result.
But I can't figure out the syntax.
Can someone share any advice on how to tackle this experiment?
Maybe I'm not understanding the problem?
They're just asking you to keep track of which number category the largest number belongs to:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largestkind = ""
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestkind = kind
}
}
}
largest
largestkind
Alternately you can use closure to make the tasks simpler.
The for loop calculate the sum of each series.
The final reduce finds the series tuple that contains maximum number.
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var sums = Array<(String, Int)>()
for (kind, numbers) in interestingNumbers {
sums = sums + [(kind, numbers.reduce(0, +))]
}
let maxSeries = sums.reduce(("", Int.min), { $0.1 > $1.1 ? $0 : $1 })
println(sums)
println(maxSeries)
Here it from playground using Xcode 8.3 and Swift 3.0
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
let largest = interestingNumbers.map{$0.value}.flatMap{$0}.max()
print(largest)
Optional(25)

Resources