Julia-lang comparison of expression and commutativity - operators

OK my title isn't great but it's easily explainable with an example.
julia>a = :(1 + 2)
julia>b = :(2 + 1)
julia>a == b
false
I have two expressions a and b. I would like to know if they will give me the same results without being evaluated.
I though that commutative operators like + or * could infer that the results would be the same.
EDIT:
Another way to understand it is to compare a very specific subset of expressions that can infer the commutativity of the function:
Expr(:call, +, a, b) <=> Expr(:call, +, b, a)

We can write a fairly simple function to check if two arrays have the same elements, modulo ordering:
function eq_modulo_ordering!(xs, ys) # note !, mutates xs and ys
while !isempty(xs)
i = findfirst(isequal(pop!(xs)), ys)
i === nothing && return false
deleteat!(ys, i)
end
isempty(ys)
end
eq_modulo_ordering(xs, ys) = eq_modulo_ordering!(copy(xs), copy(ys))
We can use then use this function to check if two top-level expressions are equivalent.
function expr_equiv(a::Expr, b::Expr, comm)
a.head === b.head || return false
a.head === :call || return a == b
a.args[1] ∈ comm || return a == b
eq_modulo_ordering(a.args, b.args)
end
expr_equiv(a, b, comm) = a == b
expr_equiv(a, b) = expr_equiv(a, b, [:+])
In the case that we want to check that two expressions are fully equivalent beyond the top-level, we could modify our functions to use mutual recursion to check if the subexpressions are expr_equiv, rather than isequal.
function eq_modulo_ordering!(xs, ys, comm) # note !, mutates xs and ys
while !isempty(xs)
x = pop!(xs)
i = findfirst(b -> expr_equiv(x, b, comm), ys)
i === nothing && return false
deleteat!(ys, i)
end
isempty(ys)
end
eq_modulo_ordering(xs, ys, comm) = eq_modulo_ordering!(copy(xs), copy(ys), comm)
function expr_equiv(a::Expr, b::Expr, comm)
a.head === b.head || return false
a.head === :call || return a == b
a.args[1] ∈ comm || return all(expr_equiv.(a.args, b.args, Ref(comm)))
eq_modulo_ordering(a.args, b.args, comm)
end
expr_equiv(a, b, comm) = a == b
expr_equiv(a, b) = expr_equiv(a, b, [:+])
We can now use expr_equiv as expected, optionally supplying a list of functions which are commutative.
julia> expr_equiv(:((a + b + b) * c), :((b + a + b) * c))
true
julia> expr_equiv(:((a + a + b) * c), :((b + a + b) * c))
false
julia> expr_equiv(:(c * (a + b + b)), :((b + a + b) * c), [:+, :*])
true

This is impossible. Figuring out whether two programs have the same result without evaluating them is called the Function Problem and is provably equivalent to solving the Halting Problem.
It is not possible to compute whether to pieces of code will have the same result.

Related

How can I find overloaded operators in Kotlin?

Given that there are plenty of overloaded operators in Kotlin standard library how can I find them and their corresponding actions for each stdlib's class that declares them?
Example: recently I have discovered that += adds an element to MutableCollection.
I could have done it by going to MutableCollections.kt and finding there a declaration ...operator...plusAssign(t: T) but ofc I had no idea that it exists and can be found exactly in that file.
Maybe there is any official reference to see them in one place?
In Operator overloading documentation page, you will find Augmented assignments.
You can use either List<T> += T or List<T>.plusAssign(T).
If you want to quickly lookup mini-doc (and you are using IntelliJ/Android Studio) you can Hold CTRL + Q, it would show a mini dialog containing enough info.
Operator overloads can be defined anywhere(including outside the standard library), so it is not practical to make a list of all operator overloads.
You can find a list of all overloads in the documentation.
To summarize the documentation the following can be overloaded:
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a++ a.inc()
a-- a.dec()
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b), a.mod(b) (deprecated)
a..b a.rangeTo(b)
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ..., i_n] a.get(i_1, ..., i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ..., i_n] = b a.set(i_1, ..., i_n, b)
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ..., i_n) a.invoke(i_1, ..., i_n)
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.remAssign(b), a.modAssign(b) (deprecated)
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0

How can I go about creating distinct variables in Idris?

I am trying to reconstruct the axioms for Hilbert's geometry in Idris. I came up with the following code to represent his axioms:
interface (Eq point) => Plane line point where
colinear : point -> point -> point -> Bool
contains : line -> point -> point -> Bool
axiom1a : (a,b : point) -> (a /= b) = True -> (l : line ** (contains l a b = True))
axiom1b : contains l a b = True -> contains m a b = True -> l = m
axiom2 : (a : point ** (colinear a b c = False) && (a /= b) = True && (b /= c) = True && (a /= c) = True)
axiom3 : (l : line) -> (a ** (contains l a b = True))
axiom2 should read "There exists 3 distinct non-colinear points." I get the following error:
When checking type of Main.axiom2:
When checking argument P to type constructor Builtins.DPair:
Type mismatch between
Bool (Type of _ && _)
and
Type (Expected type)
If I remove && (a /= b) = True && (b /= c) = True && (a /= c) = True the code runs but then the qualification of "distinct" in the axiom is lost. Any help would be appreciated.
colinear a b c = False is a Type, not a Bool. Likewise for (a /= b) = True, (b /= c) = True, and (a /= c) = True.
Instead of using &&, you must use a "type-level &&", i.e. a tuple.
axiom2 : (a : point ** (colinear a b c = False, (a /= b) = True, (b /= c) = True, (a /= c) = True))
However, that would read "There exists a point a that is not colinear with any two other distinct points", which is not always the case. You could instead write this:
axiom2 : (a : point ** (b : point ** (c : point ** (colinear a b c = False, (a /= b) = True, (b /= c) = True, (a /= c) = True))))
That would read "There exist three distinct points that are not colinear". I'm not sure if it's possible to make that any nicer to look at, like (a, b, c : point ** ....

Hofstadter Female and Male sequences in SML

This is my first SML program. I am trying to write a function that returns the first number to the nth number of Hofstadter's Female or Male sequence in list form. What I have so far is:
val m = fn (n) => if n = 0 then 1 :: [] else m f (n - 1);
val f = fn (n) => if n = 0 then 0 :: [] else f m (n - 1);
You can learn about the sequence here:
https://en.wikipedia.org/wiki/Hofstadter_sequence#Hofstadter_Female_and_Male_sequences
The error that I am getting is:
[opening sequence.sml]
sequence.sml:1.49 Error: unbound variable or constructor: f
sequence.sml:1.47-1.58 Error: operator is not a function [tycon mismatch]
operator: int list
in expression:
(m <errorvar>) (n - 1)
val it = () : unit
How can I correct this?
I ended up taking this approach:
fun
m (n) = if n = 0 then 0 else n - (f (m (n - 1)))
and
f (n) = if n = 0 then 1 else n - (m (f (n - 1)));
val seq = fn n => List.tabulate((n), f);
It is quite slow. If anybody has a faster version, then I'd love to see it.
Although you have already fixed them, there were two problems with your original approach:
Function application is left-associative in SML so m f (n - 1) was being interpreted as (m f) (n - 1), not the desired m (f (n - 1)). You can fix this by explicitly specifying the bracketing m (f (n - 1)).
To be able to call f from m and m from f, you need to use the keyword fun instead of val on the first declaration (to make the function recursive), and the keyword and instead of fun or val on the second declaration (to make the function mutually recursive with the first function). This would look like
fun f n = ... (* I can call f or m from here! *)
and m n = ... (* I can call f or m from here! *)
To make it faster, you can memoize! The trick is to make f and m take as arguments memoized versions of themselves.
(* Convenience function: Update arr[i] to x, and return x. *)
fun updateAndReturn arr i x = (Array.update (arr, i, SOME x); x)
(*
* Look up result of f i in table; if it's not found, calculate f i and
* store in the table. The token is used so that deeper recursive calls
* to f can also try to store in the table.
*)
fun memo table f token i =
case Array.sub (table, i)
of NONE => updateAndReturn table i (f token i)
| SOME x => x
(*
* Given f, g, and n : int, returns a tuple (f', g') where f' and g' are memoized
* versions of f and g, respectively. f' and g' are defined only on the domain
* [0, n).
*)
fun memoizeMutual (f, g) n =
let
val fTable = Array.array (n, NONE)
val gTable = Array.array (n, NONE)
fun fMemo i = memo fTable f (fMemo, gMemo) i
and gMemo i = memo gTable g (gMemo, fMemo) i
in
(fMemo, gMemo)
end
fun female _ 0 = 1
| female (f, m) n = n - m (f (n - 1))
fun male _ 0 = 0
| male (m, f) n = n - f (m (n - 1))
fun hofstadter upTo =
let
val (male', female') = memoizeMutual (male, female) upTo
in
(List.tabulate (upTo, male'), List.tabulate (upTo, female'))
end
I renamed f and m to female and male. The memoized fMemo and gMemo are threaded through female and male by memoizeMutual. Interestingly, if we call male', then results for both male' and female' are memoized.
To confirm it's indeed faster, try evaluating hofstadter 10000. It's much faster than the forever that your version would take.
As a final note, the only recursive functions are fMemo and gMemo. Every other function I wrote could be written as an anonymous function (val memoizeMutual = fn ..., val female = fn ..., etc.), but I chose not to do so because the syntax for writing recursive functions is much more compact in SML.
To generalize this, you could replace the array version of memoizing with something like a hash table. Then we wouldn't have to specify the size of the memoization up front.

Efficiently compute Knuth's up-arrow notation modulus

I'm already using memoization as a dictionary. Is there anything else I can do? I suspect the for loop might be able to be optimized. For reference I am computing knuth_arrow(2, 3, 9, 14**8)
memo = {}
def knuth_arrow(a, n, b, m):
if (a, n, b) in memo:
return memo[(a, n, b)]
if n == 0:
return (a*b) % m
if n == 1:
s = pow(a, b, m)
memo[(a, n, b)] = s
return s
if n > 1:
s = a
for i in range(b-1):
s = knuth_arrow(a, n-1, s, m)
memo[(a, n, b)] = s
return s

How to write a loop with an "or" condition

What would be the best way to write this statement in Java.
continue loop while either x or y equals true
I have tried these and they fail. I am not sure of the proper way to construct this statement.
while (x || y == true)
while (x | y == true)
while (y == true) || (x == true)
while (y == true) | (x == true)
Thanks in advance.
Alright, so in Java, the best way would be
while(x || y)
If x and y are Booleans. If you are testing conditions,
while(x == 5 || y == 3)
while( x == true || y == true ){
//do loopy stuff
}
This may be different for some languages, but for C based syntax languages, this should work