I have been working to understand the pumpming lemma better but I am quite stuck at proving these 2 languages is not regular:
L_1 = {(ab)^n c^m | n>=1, m>=2n }
L_2 = {(ab)^n a^k (ba)^n | k<3}
for the L_2 my approach was:
Let's say there is a number p.
Be the word z=(ab)^p a^k (ba)^p => |z| = 2p > p
and its decomposition may z=uvw with |uv| <= p & |v|>0.
It means that v= (ab)^j with 0<j<=p.
We choose i = 2 for uv^(i)w leads to (ab)^(p+j) a^k (ba)^p.
This Strings has more ab then ba, which means it does not belong to the language.
=> L_2 is not regular
I am actually confused with the (ab)^n, we should decomposed it, so it is necessary to consider different cases of v or is this sufficient?
For L_1, use the string (ab)^p c^2p and point out that pumping can only change the number of a's and b's, never c's, and pumping up will cause the string not to be of the proper form, or m to be less than 2n.
For L_2, use the string (ab)^p(ba)^p and argue that since pumping can only affect the prefix (ab)^p, if pumping keeps that part in the correct format, the number of b's will increase when pumping up, whereas the number of b's in the second part (which is deterministically found by looking after the only occurrence of bb) remains the same; so, the result can't be of the form (ab)^n a^k (ba)^n due to the mismatch in number of b's.
I have a relation R :: w => w => bool that is both transitive an irreflexive.
I have the axiom Ax1: "finite {x::w. True}". Therefore, for each x there is always a longest sequence of wn R ... R w2 R w1 R x.
I need a function F:: w => nat, that -for a given x - gives back the "lenght" of this sequence (or 0 if there is no y such that xRy). How would I go about building one in isabelle.
Also: Is Ax1 a good way to axiomatize the "finiteness of type w" or is there a better one?
First of all, a more idiomatic way of writing {x::w. True} is UNIV :: w set. I suggest writing finite (UNIV :: w set), or possibly using the finite type class, although that might make your theorem more difficult to apply because you need a finite instance for your type. I think it's not really necessary or helpful for your use case.
I then suggest the following approach:
Define an inductive predicate (using inductive) on lists of type w list stating that the first element is x and for each two successive list elements y and z, R y z holds, i.e. the list is an ascending chain w.r.t. R.
Show that any list that is such a chain must have distinct elements (cf. distinct :: 'a list ⇒ bool).
Show that there are finitely many distinct lists over a finite set.
Use the Max operator to find the biggest n such that there exists a list of length n that is an ascending chain w.r.t. R. That this works should be easy since there is at least one such chain, and you've already shown that there are only finitely many chains.
I'm currently learning programming language concepts and pragmatics, hence I feel like I need help in differentiating two subbranches of declarative language family.
Consider the following code snippets which are written in Scheme and Prolog, respectively:
;Scheme
(define gcd
(lambda (a b)
(cond ((= a b) a)
((> a b) (gcd (- a b) b))
(else (gcd (- b a) a)))))
%Prolog
gcd(A, B, G) :- A = B, G = A.
gcd(A, B, G) :- A > B, C is A-B, gcd(C, B, G).
gcd(A, B, G) :- B > A, C is B-A, gcd(C, A, G).
The thing that I didn't understand is:
How do these two different programming languages behave
differently?
Where do we make the difference so that they are categorized either
Functional or Logic-based programming language?
As far as I'm concerned, they do exactly the same thing, calling recursive functions until it terminates.
Since you are using very low-level predicates in your logic programming version, you cannot easily see the increased generality that logic programming gives you over functional programming.
Consider this slightly edited version of your code, which uses CLP(FD) constraints for declarative integer arithmetic instead of the low-level arithmetic you are currently using:
gcd(A, A, A).
gcd(A, B, G) :- A #> B, C #= A - B, gcd(C, B, G).
gcd(A, B, G) :- B #> A, C #= B - A, gcd(C, A, G).
Importantly, we can use this as a true relation, which makes sense in all directions.
For example, we can ask:
Are there two integers X and Y such that their GCD is 3?
That is, we can use this relation in the other direction too! Not only can we, given two integers, compute their GCD. No! We can also ask, using the same program:
?- gcd(X, Y, 3).
X = Y, Y = 3 ;
X = 6,
Y = 3 ;
X = 9,
Y = 3 ;
X = 12,
Y = 3 ;
etc.
We can also post even more general queries and still obtain answers:
?- gcd(X, Y, Z).
X = Y, Y = Z ;
Y = Z,
Z#=>X+ -1,
2*Z#=X ;
Y = Z,
_1712+Z#=X,
Z#=>X+ -1,
Z#=>_1712+ -1,
2*Z#=_1712 ;
etc.
That's a true relation, which is more general than a function of two arguments!
See clpfd for more information.
The GCD example only lightly touches on the differences between logic programming and functional programming as they are much closer to each other than to imperative programming. I will concentrate on Prolog and OCaml, but I believe it is quite representative.
Logical Variables and Unification:
Prolog allows to express partial datastructures e.g. in the term node(24,Left,Right) we don't need to specify what Left and Right stand for, they might be any term. A functional language might insert a lazy function or a thunk which is evaluated later on, but at the creation of the term, we need to know what to insert.
Logical variables can also be unified (i.e. made equal). A search function in OCaml might look like:
let rec find v = function
| [] -> false
| x::_ when v = x -> true
| _::xs (* otherwise *) -> find v xs
While the Prolog implementation can use unification instead of v=x:
member_of(X,[X|_]).
member_of(X,[_|Xs]) :-
member_of(X,Xs).
For the sake of simplicity, the Prolog version has some drawbacks (see below in backtracking).
Backtracking:
Prolog's strength lies in successively instantiating variables which can be easily undone. If you try the above program with variables, Prolog will return you all possible values for them:
?- member_of(X,[1,2,3,1]).
X = 1 ;
X = 2 ;
X = 3 ;
X = 1 ;
false.
This is particularly handy when you need to explore search trees but it comes at a price. If we did not specify the size of the list, we will successively create all lists fulfilling our property - in this case infinitely many:
?- member_of(X,Xs).
Xs = [X|_3836] ;
Xs = [_3834, X|_3842] ;
Xs = [_3834, _3840, X|_3848] ;
Xs = [_3834, _3840, _3846, X|_3854] ;
Xs = [_3834, _3840, _3846, _3852, X|_3860] ;
Xs = [_3834, _3840, _3846, _3852, _3858, X|_3866] ;
Xs = [_3834, _3840, _3846, _3852, _3858, _3864, X|_3872]
[etc etc etc]
This means that you need to be more careful using Prolog, because termination is harder to control. In particular, the old-style ways (the cut operator !) to do that are pretty hard to use correctly and there's still some discussion about the merits of recent approaches (deferring goals (with e.g. dif), constraint arithmetic or a reified if). In a functional programming language, backtracking is usually implemented by using a stack or a backtracking state monad.
Invertible Programs:
Perhaps one more appetizer for using Prolog: functional programming has a direction of evaluation. We can use the find function only to check if some v is a member of a list, but we can not ask which lists fulfill this. In Prolog, this is possible:
?- Xs = [A,B,C], member_of(1,Xs).
Xs = [1, B, C],
A = 1 ;
Xs = [A, 1, C],
B = 1 ;
Xs = [A, B, 1],
C = 1 ;
false.
These are exactly the lists with three elements which contain (at least) one element 1. Unfortunately the standard arithmetic predicates are not invertible and together with the fact that the GCD of two numbers is always unique is the reason why you could not find too much of a difference between functional and logic programming.
To summarize: logic programming has variables which allow for easier pattern matching, invertibility and exploring multiple solutions of the search tree. This comes at the cost of complicated flow control. Depending on the problem it is easier to have a backtracking execution which is sometimes restricted or to add backtracking to a functional language.
The difference is not very clear from one example. Programming language are categorized to logic,functional,... based on some characteristics that they support and as a result they are designed in order to be more easy for programmers in each field (logic,functional...). As an example imperative programming languages (like c) are very different from object oriented (like java,C++) and here the differences are more obvious.
More specifically, in your question the Prolog programming language has adopted he philosophy of logic programming and this is obvious for someone who knows a little bit about mathematical logic. Prolog has predicates (rather than functions-basically almost the same) which return true or false based on the "world" we have defined which is for example what facts and clauses do we have already defined, what mathematical facts are defined and more....All these things are inherited by mathematical logic (propositional and first order logic). So we could say that Prolog is used as a model to logic which makes logical problems (like games,puzzles...) more easy to solve. Moreover Prolog has some features that general-purpose languages have. For example you could write a program in your example to calculate gcd:
gcd(A, B, G) :- A = B, G = A.
gcd(A, B, G) :- A > B, C is A-B, gcd(C, B, G).
gcd(A, B, G) :- B > A, C is B-A, gcd(C, A, G).
In your program you use a predicate gcd in returns TRUE if G unifies with GCD of A,B, and you use multiple clauses to match all cases. When you query gcd(2,5,1). will return True (NOTE that in other languages like shceme you can't give the result as parameter), while if you query gcd(2,5,G). it unifies G with gcd of A,B and returns 1, it is like asking Prolog what should be G in order gcd(2,5,G). be true. So you can understand that it is all about when the predicate succeeds and for that reason you can have more than one solutions, while in functional programming languages you can't.
Functional languages are based in functions so always return the SAME
TYPE of result. This doesn't stand always in Prolog you could have a predicate predicate_example(Number,List). and query predicate_example(5,List). which returns List=... (a list) and also query
predicate_example(Number,[1,2,3]). and return N=... (a number).
The result should be unique, In mathematics, a function is a relation
between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output
Should be clear what parameter is the variable that will be returned
for example gcd function is of type : N * N -> R so gets A,B parameters which belong to N (natural numbers) and returns gcd. But prolog (with some changes in your program) could return the parameter A,so querying gcd(A,5,1). would give all possible A such that predicate gcd succeeds,A=1,2,3,4,5 .
Prolog in order to find gcd tries every possible way with choice
points so in every step it will try all of you three clauses and will
find every possible solutions. Functional programming languages on
the other hand, like functions should have well unique defined steps
to find the solution.
So you can understand that the difference between Functional and logic languages may not be always visible but they are based on different philosophy-way of thinking.
Imagine how hard would be to solve tic-tac-toe or N queens problem or man-goat-wolf-cabbage problem in Scheme.
Let's say I have a DFA with alphabet {0,1} which basically accepts any strings as long as there is no consecutive 0's (at most one 0 at a time). How do I express this in a mathematical notation?
I was thinking of any number of 1's followed by either one or none 0's, then any number of 1's..... but couldn't figure out the appropriate mathematical notation for it.
My attempt but obviously incorrect since 1010 should be accepted but the notation does not indicate so:
As a regular expression you could write this as 1*(01+)*0?. Arbitrary many ones, then arbitrary many groups of exactly one zero followed by at least one one, and in the end possibly one zero. Nico already wrote as much in a comment. Personally I'd consider such a regular expression sufficiently formal to call it mathematical.
Now if you want to write this using exponents, you could do something like
L = {1a (0 11+bi)c 0d mod 2 | a,bi,c,d ∈ ℕ for 1≤i≤c}
Writing a bit of formula in the exponents has the great benefit that you don't have to split the place where you use the exponent and the place where you define the range. Here all my numbers are natural numbers (including zero). Adding one means at least one repetition. And the modulo 2 makes the exponent 0 or 1 to express the ? in the regular expression.
Of course, there is an implied assumption here, namely that the c serves as a kind of loop, but it doesn't repeat the same expression every time, but the bi changes for each iteration. The range of the i implies this interpretation, but it might be considered confusing or even incorrect nonetheless.
The proper solution here would be using some formal product notation using a big ∏ with a subscript i = 1 and a superscript c. That would indicate that for every i from 1 through c you want to compute the given expression (i.e. 011+bi) and concatenate all the resulting words.
You could also give a recursive definition: The minimal fixpoint of the following definition
L' = {1, 10} ∪ {1a 0 b | a ∈ ℕ, a > 0, b ∈ L'}
is the language of all words which begin with a 1 and satisfy your conditions. From this you can build
L = {ε, 0} ∪ L' ∪ {0 a | a ∈ L'}
so you add the empty word and the lone zero, then take all the words from L' in their unmodified form and in the form with a zero added in front.
This is supposed to calculate the sum of two lists. The lists can be of different size.
sum([],[],[]).
sum(A,[],A).
sum([],B,B).
sum([A|Int1],[B|Int2],[C|Int3]) :-
(
C =:= A + B
;
((C =:= A), B = [])
;
((C =:= B), A = [])
),
sum(Int1,Int2,Int3).
It seems to work correctly, except when trying to find the sum of two lists. Then it gives the following error:
ERROR: =:=/2: Arguments are not sufficiently instantiated
I don't see why. There's a recursive and a basis step, what exactly is not yet instantiated and how do I fix it?
[1] While your disjunctions in the last clause are -- to some extent -- conceptually correct, Prolog considers these disjunctions in sequence. So it first considers C =:= A + B. But either A or B can be the empty list! This is what causes the error you reported, since the empty list is not allowed to occur in a numeric operation.
[2] You need to use C is A + b (assignment) i.o. C =:= A + B (numeric equivalence).
[3] If you say [A|Int1] and then A = [], then this means that [A|Int1] is not (only) a list of integers (as you claim it is) but (also) a list of lists! You probably intend to check whether the first or the second list is empty, not whether either contains the empty list.
Staying close to your original program, I would suggest to reorder and change things in the following way:
sumOf([], [], []):- !.
sumOf([], [B|Bs], [C|Cs]):- !,
C is B,
sumOf([], Bs, Cs).
sumOf([A|As], [], [C|Cs]):- !,
C is A,
sumOf(As, [], Cs).
sumOf([A|As], [B|Bs], [C|Cs]):-
C is A + B,
sumOf(As, Bs, Cs).
For example:
?- sumOf([1,2,3], [1,-90], X).
X = [2, -88, 3]
Notice my use of the cut (symbol !) in the above. This makes sure that the same answer is not given multiple times or -- more technically -- that no choicepoints are kept (and is called determinism).
You should read a tutorial or a book. Anyway, this is how you add two things to each other:
Result is A + B
This is how you could add all elements of one list:
sum([], 0). % because the sum of nothing is zero
sum([X|Xs], Sum) :-
sum(Xs, Sum0),
Sum is X + Sum0.
And this is how you could add the sums of a list of lists:
sums([], 0).
sums([L|Ls], Sums) :-
sums(Ls, Sums0),
sum(L, S),
Sums is Sums0 + S.