I came across a neat math puzzle involving counting the number of unique combinations in a hypothetical lock where digit order does not count. Before you continue, please watch at least the first minute of following video:
The rest of the video describes two related approaches for carrying out the counting. Often when I run into complex counting problems, I like to do a sanity check using brute force computation to make sure I have not missed anything. Julia is fantastic choice for doing such computation. It has C like speed, and with an expressiveness that rivals many other high level languages.
Without further ado, here is the Julia code I used to verify my solution the problem.
function unique_combs(n=4)
pat_lookup=Dict{String,Bool}()
for i=0:10^n-1
d=digits(i,10,n)# The digits on an integer in an array with padding
ds=d |>sort|>join# putting the digits in a string after sorting
get(pat_lookup,ds,false)||(pat_lookup[ds]=true)
end
println("The number of unique digits is $(length(pat_lookup))")
end
In line 2 we create a dictionary that we will be using to check if the number fits a previously seen pattern. The loop starting in line 3, examines all possible ordered combinations. The digits function in line 4 takes any integer and generate an array of its constituent digits. We generate the unique digit string in line 5 using pipes, by first sorting the integer array of digits and then combining them in a string. In line 6 we check if the pattern of digits was seen before and make use of quick short short-circuit evaluation to avoid an if-then statement.
Earlier I presented a minimal example of Julia calling C. It mimics how one would go about writing C code, wrapping it a library and then calling it from Julia. Today I came across and even more minimal way of doing that while reading an excellent blog on Julia’s syntactic loop fusion. Associated with the blog was notebook that explores the matter further.
Basically, you an write you C in a string and pass it directly to the compiler. It goes something like
using Libdl
C_code= raw"""
double mean(double a, double b) {
return (a+b) / 2;
}
"""const Clib=tempname()open(`gcc -fPIC -O3 -xc -shared -o $(Clib *"."* Libdl.dlext) -`, "w")do f
print(f, C_code)end
The tempname function generate a unique temporary file path. On my Linux system Clib will be string like "/tmp/juliaivzRkT". That path is used to generate a library name "/tmp/juliaivzRkT.so" which will then used in the ccall:
This approach would not be recommended if you are writing anything sophisticated in C. However, it is fun to experiment with for short bits of C code that you might like to call from Julia. Saves you the hassle of creating a Makefile, compiling, etc…
Recently I came across a nice Ted-Ed video presenting a Fish Riddle.
I thought it would be fun to try solving it using Julia’s award winningJuMP package. Before we get started, please watch the above video-you might want to pause at 2:24 if you want to solve it yourself.
To attempt this problem in Julia, you will have to install the JuMP package.
julia> Pkg.add("JuMP")
JuMP provides an algebraic modeling language for dealing with mathematical optimization problems. Basically, that allows you to focus on describing your problem in a simple syntax and it would then take care of transforming that description in a form that can be handled by any number of solvers. Those solvers can deal with several types of optimization problems, and some solvers are more generic than others. It is important to pick the right solver for the problem that you are attempting.
The problem premises are:
1. There are 50 creatures in total. That includes sharks outside the tanks and fish
2. Each SECTOR has anywhere from 1 to 7 sharks, with no two sectors having the same number of sharks.
3. Each tank has an equal number of fish
4. In total, there are 13 or fewer tanks
5. SECTOR ALPHA has 2 sharks and 4 tanks
6. SECTOR BETA has 4 sharsk and 2 tanks
We want to find the number of tanks in sector GAMMA!
Here we identify the problem as mixed integer non-linear program (MINLP). We know that because the problem involves an integer number of fish tanks, sharks, and number of fish inside each tank. It also non-linear (quadratic to be exact) because it involves multiplying two two of the problem variables to get the total number or creatures. Looking at the table of solvers in the JuMP manual. pick the Bonmin solver from AmplNLWriter package. This is an open source solver, so installation should be hassle free.
julia> Pkg.add("AmplNLWriter")
We are now ready to write some code.
using JuMP, AmplNLWriter
# Solve model
m = Model(solver=BonminNLSolver())# Number of fish in each tank
@variable(m, n>=1, Int)# Number of sharks in each sector
@variable(m, s[i=1:3], Int)# Number of tanks in each sector
@variable(m, nt[i=1:3]>=0, Int)
@constraints m begin
# Constraint 2
sharks[i=1:3], 1<= s[i]<= 7
numfish[i=1:3], 1<= nt[i]# Missing uniqueness in restriction# Constraint 4
sum(nt)<= 13# Constraint 5
s[1] == 2
nt[1] == 4# Constraint 6
s[2] == 4
nt[2] == 2end# Constraints 1 & 3
@NLconstraint(m, s[1]+s[2]+s[3]+n*(nt[1]+nt[2]+nt[3]) == 50)# Solve it
status = solve(m)
sharks_in_each_sector=getvalue(s)
fish_in_each_tank=getvalue(n)
tanks_in_each_sector=getvalue(nt)
@printf("We have %d fishes in each tank.\n", fish_in_each_tank)
@printf("We have %d tanks in sector Gamma.\n",tanks_in_each_sector[3])
@printf("We have %d sharks in sector Gamma.\n",sharks_in_each_sector[3])
In that representation we could not capture the restriction that “no two sectors having the same number of sharks”. We end up with the following output:
We have 4 fishes in each tank.
We have 4 tanks in sector Gamma.
We have 4 sharks in sector Gamma.
Since the problem domain is limited, we can possible fix that by adding a constrain that force the number of sharks in sector Gamma to be greater than 4.
@constraint(m,s[3]>=5)
This will result in an answer that that does not violate any of the stated constraints.
We have 3 fishes in each tank.
We have 7 tanks in sector Gamma.
We have 5 sharks in sector Gamma.
However, this seems like a bit of kludge. The proper way go about it is represent the number of sharks in the each sector as binary array, with only one value set to 1.
# Number of sharks in each sector
@variable(m, s[i=1:3,j=1:7], Bin)
We will have to modify our constraint block accordingly
We invent a new variable array st to capture the number of sharks in each sector. This simply obtained by multiplying the binary array by the vector \([1,2,\ldots,7]^\top\)
After the model has been solved, we extract our output for the number of sharks.
sharks_in_each_sector=getvalue(st)
…and we get the correct output.
This problem might have been an overkill for using a full blown mixed integer non-linear optimizer. It can be solved by a simple table as shown in the video. However, we might not alway find ourselves in such a fortunate position. We could have also use mixed integer quadratic programming solver such as Gurobi which would be more efficient for that sort of problem. Given the small problem size, efficiency hardly matters here.
Recently I ran into problem where I was trying to read a CSV files from a Scandinavian friend into a DataFrame. I was getting errors it could not properly parse the latin1 encoded names.
I tried running
using DataFrames
dataT=readtable("example.csv", encoding=:latin1)
but the got this error
ArgumentError: Argument 'encoding' only supports ':utf8' currently.
The solution make use of (StringEncodings.jl)[https://github.com/nalimilan/StringEncodings.jl] to wrap the file data stream before presenting it to the readtable function.
In the above, the big integer is the magic number that lets us generate the image of the formula. I also need to setprecision of BigFloat to be very high, as rounding errors using the default precision does not get us the desired results. The implementation was inspired by the one in Python, but I see Julia a great deal more concise and clearer.
In [2]:
function tupper_field(k)field=Array{Bool}(17,106)for(ix,x)inenumerate(0.0:1:105.0),(iy,y)inenumerate(k:k+16)field[iy,107-ix]=1/2<floor(mod(floor(y/17)*2^(-17*floor(x)-mod(floor(y),17)),2))endfieldend
Recently, I came across a fascinating blog and video from Mind your Decisions. It is about how a fraction
\(\frac{1}{999,999,999,999,999,999,999,998,,999,999,999,999,999,999,999,999}\)
would show the Fibonacci numbers in order when looking at its decimal output.
On a spreadsheet and most standard programming languages, such output can not be attained due to the limited precision for floating point numbers. If you try this on R or Python, you will get an output of 1e-48. Wolfram alpha,however,allows arbitrary precision.
In Julia by default we get a little better that R and Python
We observe here that we are getting the first few Fibonacci numbers \(1, 1, 2, 3\). We need more precision to get more numbers. Julia has arbitrary precision arithmetic baked into the language. We can crank up the precision of the BigFloat type on demand. Of course, the higher the precision, the slower the computation and the greater the memory we use. We do that by setprecision.
That is looking much better. However it we be nice if we could extract the Fibonacci numbers that are buried in that long decimal. Using the approach in the original blog. We define a function
y(x)=one(x)-x-x^2
and calculate the decimal
a=1/y(big"1e-24")
Here we use the non-standard string literal big"..." to insure proper interpretation of our input. Using BigFloat(1e-24)) would first construct at floating point with limited precision and then do the conversion. The initial loss of precision will not be recovered in the conversion, and hence the use of big. Now we extract our Fibonacci numbers by this function
function extract_fib(a)
x=string(a)
l=2
fi=BigInt[]push!(fi,1)for i=1:div(length(x)-24,24)
j=parse(BigInt,x[l+1+(i-1)*24:l+i*24])push!(fi,j)end
fi
end
Here we first convert our very long decimal number of a string and they we exploit the fact the Fibonacci numbers occur in blocks that 24 digits in length. We get out output in an array of BigInt. We want to compare the output with exact Fibonacci numbers, we just do a quick and non-recursive implementation.
function fib(n)
f=Vector{typeof(n)}(n+1)
f[1]=f[2]=1;for i=3:n+1
f[i]=f[i-1]+f[i-2]end
f
end
Now we compare…
fib_exact=fib(200);
fib_frac=extract_fib(a);for i in eachindex(fib_frac)println(fib_exact[i], " ", fib_exact[i]-fib_frac[i])end
We get a long sequence, we just focused here on when the discrepancy happens.
The output shows that just before the extracted Fibonacci number exceeds 24 digits, a discrepancy occurs. I am not quite sure why, but this was a fun exploration. Julia allows me to do mathematical explorations that would take one or even two orders of magnitude of effort to do in any other language.
Recently I was using Julia to run ffprobe to get the length of a video file. The trouble was the ffprobe was dumping its output to stderr and I wanted to take that output and run it through grep. From a bash shell one would typically run:
you will get errors. Julia does not like pipes | inside the backticks command (for very sensible reasons). Instead you should be using Julia’s pipeline command. Also the redirection 2>&1 will not work. So instead, the best thing to use is and instance of Pipe. This was not in the manual. I stumbled upon it in an issue discussion on GitHub. So a good why to do what I am after is to run.
This would create a pipe object p that is then used to capture stderr after the execution of the command. Next we need to close the input end of the pipe.
julia>close(p.in)
Finally we can use the pipe with grep to filter the output.
I can across an exotic number system known as a sandpile on Numberphile video.
Exploiting Julia fantastic type system and very cool index handling, I put implements that sandpile addition operator demonstrated in the Numberphile video.
I was recently introduced to Kaperkar’s Constant.
It is quite magical. You take any four digit number \(A\), sort the digits from highest to lowest to create a new number \(A^{\text{high}}\), sort the digits from lowest to highest to get \(A^{\text{low}}\), and calculate and new number \(A= A^{\text{high}}- A^{\text{low}}\). You repeat this procedure enough times and you end up with \(A=6174\).
I made a nifty implementation of that in Julia below.