Pollard Rho implementation in APL - primes

Recently, I have tried to work using APL but have had difficulty conceptualizing it. For instance, let's say I want to make a program g<-pollard x, where the function computes if a number x is prime or factorable through the Pollard-Rho method.
I know the method itself, but I don't know where to start actually integrating it into APL. Should I start by creating an entirely new function f(x) for use in this function, or should I include everything in the code? How would I go about saving the x from the previous run to use for the next run? Note that I'm not asking for an entire program, just some recommendations to get me started.

First off, this is a bit more than trivial for trying out a language you do not know. Be that as it may, I found the problem intriguing and have whipped up a couple of solutions for you. These are done using Dyalog APL. For an APL novice they will require some study.
The first solution is a simple function for Pollard Rho (as defined by Wikipedia), with the f(x) embedded directly in the main function:
PollardRho←{
n←⍵
⍺←2 2 1
x y d←⍺
f←{n|1+⍵*2}
x←f x
y←f f y
d←n∨|x-y
d=n:'Failure'
d≠1:d
x y d ∇ n
}
We can try this out in the APL session:
PollardRho 8051
97
The second method extracts the function f(x) from the main function, and provides it as an argument, which is convenient for using different functions for f(x). In APL, a function that takes a function as an argument is called an operator:
PollardRho2←{
n←⍵
⍺←2 2 1
x y d←⍺
x←n ⍺⍺ x
y←n ⍺⍺ n ⍺⍺ y
d←n∨|x-y
d=n:'Failure'
d≠1:d
x y d ⍺⍺ ∇∇ n
}
We can run this in the session by first defining the function f(x) and providing it as the left operand:
f←{⍺|1+⍵*2}
f PollardRho2 8051
97
Note that both solutions use tail recursion.
I hope you find this useful.

Related

sympy: sympy function symbolic or non-symbolic

I am trying to understand about sympy's symbolic functions:
import sympy
from sympy.abc import x,y,z
with sympy.evaluate(False):
print(sympy.sympify("diff(x,x)").func)
print(sympy.parse_expr("diff(x, x)", local_dict={'diff':sympy.Derivative}).func)
print(sympy.sympify("Derivative(x,x)").func)
pass
This puts out:
Piecewise
<class 'sympy.core.function.Derivative'>
<class 'sympy.core.function.Derivative'>
This example should illustrate that diff is not a symbolic function yet Derivative is.
sympy.sympify("diff(x,x)").func results in Piecewise.
What exactly makes a function in sympy 'symbolic'?
Why don't both of the functions belong to <class 'sympy.core.function.Derivative'>?
I tried to test on a few examples if a function is symbolic using:
list_of_funcs = [sin, cos, tan, sec, csc, cot, sinh, cosh, tanh, sech, csch, coth, asin, acos, atan, asec, acsc, acot, asinh, acosh, atanh, asech, acsch, acoth, log, log, log, exp, <class 'sympy.concrete.summations.Sum'>, <class 'sympy.concrete.products.Product'>, Piecewise, jacobi, Piecewise]
with sympy.evaluate(False):
for f in list_of_funcs:
if issubclass(f, sympy.Basic):
print(f'{f}: True')
It returned True for all yet as far as I understood Piecewise is not symbolic.
Could you help me finding a way to test if a function is symbolic?
Answering this question without going too deep into coding concepts is not easy, but I can give it a try.
SymPy exposes many functions:
cos, sin, exp, Derivative, Integral... we can think of them as symbolic functions. Let's say you provide one or more arguments, then:
the function might evaluate to some symbolic numerical value. For example, cos(0) will return the symbolic number 1.
the function might return an "unevaluated" object. For example, cos(x) returns cos(x): this is a symbolic expression of type cos (as you have seen by running the func attribute). Similarly, you can create a derivative object Derivative(expr, x): this is a symbolic expression that represents a derivative, it doesn't actually compute the derivative!
Unevaluate functions, for example Function("f")(x), which will render as f(x): this is a symbolic expression of type f.
diff, integrate, series, limit, ... : those are ordinary python functions (for example, created with def diff(...)) that are going to apply some operation to a symbolic expression. When you call diff(expr, x) you are asking SymPy to compute the derivative of expr with respect to x. What if you wanted to represent the derivative without actually computing it? You write Derivative(expr, x).
So, going back to your example:
sympy.parse_expr("diff(x, x)", local_dict={'diff':sympy.Derivative})
this can be easily simplified to:
sympy.parse_expr("Derivative(x, x)")
A few more "relationships":
diff and Derivative
integrate and Integral
limit and Limit
Think of "symbolic" functions as nouns and "non symbolic" as verbs.
noun-like verb-like
---------- ---------
Integral integrate
Derivative diff
Sum summation
Product product
Those that are Python functions (I think what you mean by non-symbolic) emit some evaluated form of something that could also exist in an unevaluated form, e.g. prod(x, (x, 1, 5)) -> 120; Product(x, (x, 1, 5)) -> no change.
It would be better to refer to them in some other way. What I think you mean is "evaluated" vs "non-evaluated" (since almost all of SymPy's functions will return SymPy objects with "symbols", even if numeric).
If the type(thing) -> function it is not a class itself, it is a Python function. If you check the type of cos or Sum you will not get function as the result.
Whereas some of the evaluates and unevaluated forms may have different names (Sum vs summation) others, like Add are evaluative by default but you can use the evaluate=False arg to stop that: Add(x, x) = x + x != Add(x,x,evaluate=False). Those which are evaluative can be made non-evaluative by passing evaluate=True, e.g. Derivative(x, x, evaluate=True) -> 1.

Compare real list in sml

For the next code I'm getting an error:
fun epoly(L:real list, x:real)=
= if L = [] then 0.0 else (epoly(tl(L:real list), x:real));;
Error:
stdIn:42.1-42.57 Error: operator and operand don't agree [equality type required]
operator domain: ''Z * ''Z
operand: real list * 'Y list
in expression:
L = nil
Since you're not actually asking a question, it is a little unclear what your intent is. Presumably this is attempted code that doesn't work and the accompanying error message, and the implicit question is "Why doesn't this code work? What am I doing wrong, and what can I do to improve it?" But really that's guesswork, and those are lazy questions, too.
Here's how your post could look like if my assumptions above are correct and you want positive feedback in the future:
I am trying to write a function that evaluates a polynomial with real coefficients L for the variable x.
It looks like:
fun epoly (L : real list, x : real) =
if L = [] then 0.0 else epoly(tl L, x)
Unfortunately I am getting a type error that I don't understand:
stdIn:1.35-1.91 Error: operator and operand don't agree [equality type required]
operator domain: ''Z * ''Z
operand: real list * 'Y list
in expression:
L = nil
What does this error mean, and if this is not the right way to evaluate a polynomial, then what would another way to accomplish the same thing look like?
The take-aways:
Write what your problem is, don't let others assume what your problem is. Making a question easily understood makes people want to answer your question, and describing your problem in words tells what you think is the problem, so that people don't try and answer the wrong question. In this case, your question could have been "Under what version of the Standard ML specification were reals removed as an eqtype?" and a sufficient answer would have been '97. But would you have been happy about that answer?
Once you know how to ask the right question, you can also better google around (e.g. search for: evaluate polynomial "standard ml"|sml) and find that there exists code from which you can let yourself inspire: here, here, here.
Format your code nicely and make sure it works. Use StackOverflow's Markdown to format your code nicely. The code that you posted contains artifacts from the interactive REPL (an extra =), so anyone who copy-pastes it into a REPL will get an error, will have to figure out where it occurred, fix it, and then start to think about what could be the problem, since you didn't say. A good rule is to test that the code you posted works by copy-pasting it once you've asked the question. One can easily forget to include a non-standard function.
An answer, assuming my rendition of your "question" somewhat lines up with your intent:
When you do if L = [] ... then you're using equality for lists of reals, which in turn relies on equality for reals, but reals can't be compared for equality. See the Q&A "Why can't I compare reals in Standard ML?" You can test if a list of reals is empty without comparing reals by doing e.g.:
fun epoly (L, x) =
if null L then 0.0 else epoly (tl L, x)
This is because the standard library function null uses pattern matching on lists but does not address the list's elements, whereas = assumes that elements may have to be compared. Even though that never happens in practice in the example L = [], this is still an error in the type system.
If you were comparing reals for equality, consider using an epsilon test. Besides that, consider using pattern matching instead of hd and tl because those functions can fail and crash because they're partial:
fun epoly ([], x) = 0.0
| epoly (c::cs, x) = epoly (cs, x)
All this function does is throw away its second argument x, traverse its first argument, c::cs, and do nothing with each coefficient c. Presumably, in order to evaluate a polynomial, you must do something to coefficient c and x before doing the same thing recursively on the remaining coefficients cs and x, and then somehow compose those.

Questions on SML type ckecking and inference

First of all, since the question is somehow related to a school project I don't think that posting my code is appropriate. Plus, as I explain later on I only have a modified version of the code in question.
And I explain myself. I should implement a version of Dijkstra's algorithm using a priority queue. I thought that a simple functional way to do so is define a dijkstra function with inputs the queue and the targeted node and a helper function to enqueue the nodes that are neighbors to the element of the list that was just dequeued. Unfortunately, the helper function did't typecheck - Unresolved Flex Record.
So far it may seem that the code is important but allow me to add one more
detail. Since the graph was 4-canonical(meaning each node has exactly four neighbors) I represented it as a matrix using modulus arithmetic. In order to simplify my algorithm I used this fact to rewrite it and use 4 extra helper functions - one for each move possible - instead of four ifs inside the first helper function. Each of the four-move function returns true if we should visit this node (meaning the cost we will need this way is smaller than the current cost needed) and false if not. And the first helper simply returns a tuple of four booleans variables. Finally, I copied the enqueue code that wasn't working in my first try into the body of the dijkstra code and suddenly it did typecheck.
I understand that it may still be unclear and perhaps you can only speculated about what was going on. But I am truly very puzzled.I searched this site and SML basis as well and found that this kind of error occurs in the following case:
f (x,y,z) = ...
where z isn't used so the checker can't deduct what it is.
I am sure this is not the case in my problem since I just copy-paste the code(not a very good technique I know but ok). Hence, I concluded that the problem was the typechecker not working with functions calls. I searched again and found a Hindley Miller algorithm explanation. And from what I understood every time it encounters and a function will assume is a->b as the first step and later on will go to the definition of the function and complete the task. So I was back to square one and decided to ask this question here looking for a better understanding of type inference or for a hint of what has going on.
P.S. 1) Even though I tried my best to explain the question I it is still unclear or too broad let me know and I will delete,no problem.
P.S. 2) A smaller and simpler question: I read that #1 is not adviceable to take the 1st element of a tuple and sometimes it doesn't even typecheck
and instead it should be used pattern matching. Could you explain that?
P.S. 3) Someone may wonder why I asked this question since I solved the problem with my second try. Personally, I don't consider solved but hidden.
Thanks in advance and sorry for the size of the question.
Links:
SML/NJ Errors
P.S. 2)
Hindley-Miller
UPDATED: After some extra searching I have a guess about what was wrong. I was implementing a priority queue not customized for my problem but more general. So, the inference of the priority queue type was taking place when I first enqueued an element. But after enqueueing my source node and calling dijkstra the queue would be empty once more (my dijsktra was dequeueing the first element checking if it is the target node) and the first call of the helper function that add nodes would have an empty queue as one of its arguments. Perhaps the empty queue has no type and that was causing the error?
I'm taking a guess at what you're asking.
I have a function enqueue that does not work in one context, but it does work in another. Why? It uses the #1 macro, and I read that #1 is not adviceable to take the 1st element of a tuple and sometimes it doesn't even typecheck and instead it should be used pattern matching.
In Standard ML, #1 is a macro. It behaves like a function, but unlike functions, it is overloaded for any tuple/record with a 1 field in it. If you do not specify what kind of tuple you're passing to a function, using #1 will not disambiguate this. For example,
- fun f pair = #1 pair;
! Toplevel input:
! fun f pair = #1 pair;
! ^^
! Unresolved record pattern
But giving it the type (either through explicit type annotation, or in a context where the type can be inferred by other means) works well.
- fun f (pair : int * int) = #1 pair;
> val f = fn : int * int -> int
I don't know if I'd label #1 as a definite no-go and pattern matching as the only option, [edit: ... but this Stack Overflow answer that Ionuț G. Stan linked to has some arguments.]
There are advantages and disadvantages with both. Alternatively you can make unambiguous getters that only work on the type of tuple you're working with. For example,
fun fst (x, _) = x
fun snd (_, y) = y

Sympy: Howto to rewrite erf function

I have an expression in SymPy that involves the normal cumulative function, N(x) which is directly linked to the error function through the equation N(x)=0.5*erf(x/sqrt(2)) + 0.5.
When I use the Normal(0,1).cdf(x) function of SymPy, it is written using the error function. So, when I output latex string of some (complicated) expression, the seem more complicated when using erf (instead of N(x), it outputs the equation mentionned obove). I tried to define a symbol N=0.5*erf(x/sqrt(2)) + 0.5 and tried the command 'rewrite' the rewrite my expression in terms of N, but 'rewrite' seems to work only with internally defined functions.
Does any bodu know how to rewrite erf(some_expression) in terms of N(some_expression), given that I don't know some_expression in advance (can't use subs) ?
Thanks in advance
I take it from your question that you are using Normal from sympy.statistics. You should move to sympy.stats. sympy.statistics has been deprecated for some time, and will be removed in the next version of SymPy.
To answer your question more directly, you can replace functions with functions using replace, like expr.replace(erf, lambda x: (N(x) - 0.5)/0.5).
The problem here is that there is no function N. I would expect this to be done better in sympy.stats, where the distributions are represented symbolically. However, I didn't find a way to do it. I opened https://github.com/sympy/sympy/issues/7819 for this.

Using Brent algorithm to find the root of a function f with an initial guess, but without intervals [a,b] s.t. f(a)f(b)<0

I would like to know how to use Brent algorithm if no opposite signs can be provided.
For example, in the C++ library of Brent algorithm, the root-finding procedure that implements Brent’s method has to be used, following the header file, in the form of
double zero ( double a, double b, double t, func_base& f );
where a, b satisfies the condition of opposite signs: f(a).f(b) < 0
In my problem setting, I need to find the root(s) of a black-box function f. An initial guess is provided but no endpoints a,b, such that f(a) f(b)<0 are provided It seems that in Matlab there is a function fmin that only needs an initial guess. I would like to know how to do this using C++, in particular, using the implementation of Brent such as the one linked above?
Thanks for your ideas.
Without doing exhaustive search (and in the case of real valued function, you cannot, since the value of x is uncountable), there is no way to really guarantee finding the root if such exist.
One heuristic approach to address the problem is using gradient descent, in order to minimze (/maximize) the value of the function, until you find a local minimum (/maximum) or until you find a root.
The problem with this approach is you can get stuck in a local minimum (/maximum) before finding the root, and "think" there is no root, even if one does exist.
Under the assumptions that
f is a black-box, i.e. it can be evaluated but no information on its shape is known whatsoever.
You have to use a method that requires a priori knowledge of an interval [a,b] which brackets a root of f (assuming f is continuous).
I think your only option is to make a preliminary search for two valid points a and b.
This can be done in a number of ways. The most simple-minded could be to run a linear search (with some prescribed step) starting from your initial guess, which can be repeated with a finer step if it turns out unsuccessful. If f is not too "weird" a simple method should do.
Clearly, some basic clue on the properties of f is always necessary, for example that it actually has a root and that it is continuos, differentiable, etc.. All root finding methods (gradient descent, Newton-Raphson, bisection, etc.) assume some basic properties of the function.