Prove that if ϵ ∈ L1 then L2 ⊆ L2 • L1 - set

Let L1, L2 be languages such that L2 is not the empty language.
Prove that if the empty word epsilon in L1, then L2 is a subset of L2•L1.
Assume towards a contradiction that L2 ⊈ L2•L1.
Thus, the language L1 contains words that are not the empty word, otherwise we could take ϵ and concatenate it to every word in L_2.
So ϵ ∉ L1 which is a contradiction.
Is that a good proof?
Thanks!

It looks fine. Have another one:
(1) ɛ•ω=ω•ɛ=ω for ∀ω∊L2;
(2) From (1) → ω∊L2•{ɛ} for ∀ω∊L2;
(3) From (2) and ɛ∊L1 → ω∊L2•L1 for ∀ω∊L2;
(4) From (3) and ω=ω for ∀ω∊L2 → L2=L2•L1 for L1={ɛ};
(5) If |L2⋂L2•L1|>0 then L2⊂L2•L1, where |X| is the number of elements in X;
(6) From (4) and (5) → L2⊆L2•L1
(5) Means "if new elements are actually created from the concatenation", which can be proven by giving an example of at least one such case:
L1={ɛ,a}
L2={b}
L2•L1={b,ba}
{b}⋂{b,ba}={ba}
|{ba}|=1
Its worth noting that, you can get equality when L1 has more elements than ɛ.
If |L2⋂L2•L1|=0 then L2=L2•L1
For example:
L1={ɛ,a}
L2=a+
L2•L1=L2=a+

Related

Understanding this bubble sort solution in Prolog

How does this bubble sort solution work in Prolog?
bubblesort([], []).
bubblesort([H], [H]).
bubblesort([H|D], R) :-
bubblesort(D, E),
[B|G] = E,
( (H =< B, R = [H|E])
; (H > B, bubblesort([B,H|G], R))
).
Here is an example trace: https://pastebin.com/T0DLsmAV
I understand the the line bubblesort(D,E), is responsible for sorting it down to one element, but I don't understand how this works. I understand the basics of lists in prolog, but still cannot work out how this solution operates.
The main difficulty with this code is that bad variable names were chosen and are making the logic harder to follow than it needs to be.
The first two cases are obviously base cases. The first says "the empty list is already sorted" and the second says "a singleton list is already sorted." This should make sense. The third case is where things get interesting.
Let's examine the first part.
bubblesort([H|D], R) :-
bubblesort(D, E),
All that's happened so far is we've named our result R and broken our inputs into a first element H and a tail D. From there, we have said, let's bubblesort the tail of our input and call that E. Maybe this would be a little easier to follow?
bubblesort([H|T], Result) :-
bubblesort(T, TSorted),
Next up,
[B|G] = E,
Again, bad names, but what the author is intending to do here is straightforward: take apart the result of sorting the tail so we can talk about whether the next item in the sorted tail is the right element for that position, or if it needs to switch places with the head of our input. Let's rename:
[HeadOfTSorted|RestOfTSorted] = TSorted,
Now we have a condition. Think of it in terms of prepending onto a sorted list. Say you have some element, like 3, and I hand you a sorted list. You want to determine if your 3 goes at the front or somewhere else. Well, suppose I gave you a sorted list that looked like [5,7,19,23,...]. You'd know that your 3 is right where it needs to be, and you'd hand back [3,5,7,19,23,...]. That's exactly the first case of the condition:
( (H =< HeadOfTSorted, Result = [H|TSorted])
Now consider another case, where I hand you a list that starts with [1,2,...]. You know you can't just put the three at the start and give me back [3,1,2,...]. But you don't really know where the 3 goes; it just doesn't go at the start. So what you have to do is resort the rest of the list with the 3 at the start, after the 1: [1 | resorted([3,2,...])]. That's effectively the other branch of the condition:
; (H > HeadOfTSorted, bubblesort([HeadOfTSorted,H|RestOfTSorted], R))
).
Hope this helps!
note: the key to recursive problem solving is exactly not to think about the minutiae of our code's operations. Imagine you already have the solution, then just use it to solve a smaller subproblem, thus arriving at the full problem's solution.
Your code, with more suggestive variable names so I could follow it, reads:
bubblesort([], []). % empty list is already sorted
bubblesort([H], [H]). % singleton list is already sorted
bubblesort([H|T], S) :- % `[H|T]` sorted is `S`, *if*
bubblesort(T, [M|R]), % `T` sorted is `[M|R]`, *and*
( % *either*,
H =< M, % in case `H` is not greater than `M`,
S = [H,M|R] % `S` is `[H,M|R]`,
; % *or*
H > M, % in case `H` is greater than `M`,
bubblesort([M,H|R], S) % `S` is `[M,H|R]` sorted by the same algorithm
).
(H is for "head", T is for "tail", S is "sorted", R "rest" and M is "minimum" -- see below for that).
We prove its correctness by structural induction. The induction hypothesis (IH) is that this definition is correct for shorter lists. We need to prove it is then also correct for a longer list. Indeed T is one-element shorter than [H|T]. Thus IH says [M|R] is sorted. This means M is the minimum element in T. It also means T is non-empty (sorting doesn't change the number of elements), so the clauses are indeed mutually-exclusive.
If H is not larger than the minimum element in T, [H,M|R] is obviously sorted.
Otherwise, we sort [M,H|R]. M is the minimum element and thus guaranteed to be the first in the result. What's actually sorted is [H|R], which is one element shorter, thus by IH sorting it works. QED.
If the last step sounds fishy to you, consider replacing the second alternative with the equivalent
; H > M, % in case `H` is greater then `M`,
bubblesort([H|R], S1), % `S1` is `[H|R]` sorted by the same algorithm
S = [M|S1]
).
where the applicability of the induction step is even clearer.
I'm not so sure it's a bubble sort though.
update: Indeed, measuring the empirical orders of growth, its number of inferences grows as ~ n3 (or slower), but true bubble sort clocked at ~ n2.1 (close enough to the theoretical ~ n2), where n is the list's length:
tbs([], []). % 'true' bubble sort
tbs([H],[H]).
tbs(L,S):- bubble(L,B),
( L==B -> S=L ; tbs(B,S) ).
bubble([],[]).
bubble([A],[A]).
bubble([A,B|C],R):-
( A =< B -> bubble([B|C],X), R=[A|X]
; bubble([A|C],X), R=[B|X] ).

Split a list multiple time in Prolog

this my code :
div2(L,N,L1,L2) :-
length(L1,N),%n=4
append(L1,L2, L),
L=L2,L1=[],L2=[].
i want it to display each time in L1 a 4 element list but it return false.
example :
L=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
L1=[1,2,3,4]
L1=[5,6,7,8]
L1=[9,10,11,12]
L1=[13,14,15,16]
how can i make it work. and thanks for the help.
Assuming you want div(L,N,L1,L2) to be that L1 is the first N element of L, and L2 is what remains:
div2(L,N,L1,L2) :-
length(L1,N),
append(L1,L2,L).
There are no other conditions that need to be placed on L, L1 or L2.
If you want to be the first 4 elements after some multiple of 4 elements, and L2 to be the rest, you need to say so:
div2(L,N,L1,L2) :-
append(L01,L2,L), % break up L
length(L01,Nx), % make sure prefix's length is multiple of N
0 is mod(Nx,N),
append(L0,L1,L01),% set L1 to be last N elements of prefix
length(L1,N).
A slightly different solution...
div2([X|Xs], N, P) :-
( length(P1, N),
append(P1, R, [X|Xs])
-> ( P = P1
; div2(R, N, P)
)
; P = [X|Xs]
).
This solution defines a list P1 of length N, and attempts to unify it (with append as a prefix list of [X|Xs]. ([X|Xs] is used instead of L to ensure that the predicate succeeds only if the first argument is a list with at least one element.)
If the append is successful, then the solution is either P1 (P is unified with P1) or a recursive call to div2 with the remainder of the first argument list with the prefix P1 absent.
If the append fails (which will happen if the number of partition elements N is larger than the first argument list length), then P is unified with the first argument list.

algorithm- for counting pairwise mutual occurrences

I have a list of lists.
L1= [[...][...][.....].....]
If I take all the elements after flattening the list and extract unique values from it then i get a list L2.
I have another list L3 which is some subset of L2.
I want to find the pair-wise mutual occurrences of the elements of L3 in L1. Relation is non-directed. i.e. a,b is same as b,a
eg-
L1= [[a b c d][a b d g f][c d g][d g]....]
L2=[a b c d g f]
say L3 = [c d g]
I want to find pair wise mutual occurrences of L3 in L1. i.e these values.
c,d:2
d,g:3
c,g:1
I'm getting O(n*n*m*p); where- p- no. of lists in L1, m - avg. no. of elements in each list of L1. n - no. of elements in L3.
Can I get an improved complexity?
Code for above in python is:
Here sig_tags is L3 and tags is L1.
x=[]
for i in range(len(sig_tags)):
for j in range(i+1,len(sig_tags)):
count=0
for k in tags:
if (sig_tags[i] in k) and (sig_tags[j] in k):
count+=1
if count>param:
x.append([sig_tags[i],sig_tags[j],count])
return x
Yes you can.
Give each element an id, then convert the list L1 into a list of bit vectors, where a bit is true if that list constains the corresponding letter. This is O(m*p), or O(M*p*log|Alphabet|) depending how you implement it.
Now to check if a pair belongs to a list you need to check if cerain 2 bits are true which is O(1). So all the checks are going to be O(n^2*p).
Overall the complexity is O(n^2*p + m*p).
You can skip assiging ids if you use a hash function. Be careful, sometimes the hash function computation is expensive.

Transforming recursion into tail recursion?

I am trying to write a predicate that recursively finds the nth power of some number
[A^n = A * A^(n-1)] and uses the shortcut A^(2n) = A^n * A^n.
Here is the solution so far.
p(_,0,1):-!.
p(A,N,R):-N mod 2=0,!,N1=N/2,p(A,N1,R1),R=R1*R1.
p(A,N,R):-N1=N-1,p(A,N1,R1),R=R1*A.
Now I want to make this tail recursive. I can do tail for simple cases, such as factorials and power without the shortcut (by adding an accumulator), but this one is hard.
Any help is much appreciated!
It seems it is sort of possible after all, just start it from the other end:
pow(A,N,R) :-
pow(A,N,A,1,R).
pow(_,N,R,N,R) :- !.
pow(A,N,Acc,M,R) :-
M =< N div 2, !,
M1 is M*2,
NewAcc is Acc * Acc,
pow(A,N,NewAcc,M1,R).
pow(A,N,Acc,M,R) :-
M < N,
M1 is M+1,
NewAcc is A * Acc,
pow(A,N,NewAcc,M1,R).
It applies the shortcut up to the highest power of 2 smaller than N, which is admittedly not the same as what your algorithm is doing.
Boris is right in that what his algorithm does is not the same as the original one. But here is how you can reproduce it, if you really want to:
Observe that you can determine the order of the operations from the binary representation of the number. Let N=7, then binary N=111, denoted as N=7~111.
Now you see the scheme in your original algorithm:
N Op N'
7~111 Mul 6~110 (= zero last bit)
6~110 Squ 3~011 (= shift right)
3~011 Mul 2~010
2~010 Squ 1~001
1~001 Base
Considering that due to the recursive nature of the algorithm, these steps are carried out top-to-bottom, you get Base - Squ - Mul - Squ - Mul = ((A*A)*A)*((A*A)*A))*A = A**7
Contrast this to Boris' algorithm:
N Op N'
1~001 Squ 2~010 (=shift left)
2~010 Squ 4~100 (=shift left)
4~100 Mul 5~101 (=add one)
5~101 Mul 6~110 (=add one)
6~110 Mul 7~111 (=add one)
So this one does all the shifting first, while the original considers each bit except for the first of N, right to left, in turn, "queuing" (because of bottom-up) Mul, Squ if the bit is set or just Squ if it is unset.
To reproduce this behavior (which is more efficient, as you will never do more simple multiplications than squares), you could start with N in binary and do the following (here in general pseudocode, easy for you to translate into prolog):
Acc=A
for i in (reverse(tail(bits(N)))):
Acc*=Acc
if i==1:
Acc*=A
This is for N>=1. N=0 is a special case and must be treated separately.
I'm pretty sure this is correct. If you have doubts, then just think about your original algorithm: testing for mod 2 == 0 is the same as testing if the last bit is zero. And if it is not, then substracting one is the same as zeroing out the last bit while doubling and halving is just shifting left or right in binary.

How do parenthesis work?

I wrote an algorithm and tried to implement it in Prolog, but what I found out is that the parenthesis do not work as expected: what is written in is not all done before exiting the parenthesis. Here is the code:
%1. If the first member of L1 is smaller than L2
% A. If the first member of L1 is not equal to Last
% Than: A.1 Add the first member of L1 to the first member of NL
% Begin recurssion on the resumption of L1, L2 resumption of NL
% and Last from L1.
% Else: A.2 begin the recursion on resumption of L1, L2 with the
% first member and L3 with the first member.
% 2. If the first member in L1 is equal to the first member of L2,
% Than: Start recursion on resumption of L1 and L2 (with its first
% member) and Last = *.
% 3. If the first member of L1 is bigger than the first membber of L2
% Than: begin recursion on L1 with the first member, resumption of
% L2 and Last = x. %(x != * only for debugging)
%
*/
make_list([X1|L1], [X2|L2], [X3|NewL], Last) :-
(
X1 < X2,
(
X1 \= Last, %A
X3=X1;
make_list(L1, [X2|L2], NewL, X1) %B
), %Why those parenthesis do not work as expected?
! %green cut
);
(
X1=X2,
make_list(L1, [X2|L2], [X3|NewL], *)
),
!
;
make_list([X1|L1], L2, [X3|NewL], *).
My question is how to make it work as expected and why does B not work once A is done? After all it is also in the same parenthesis, e.g.:
?- make_list([6,6,10,20],[10,25,30],L, -).
L = [6|_G849] % (should be [6,20]).
EDIT1: make_list should find all members in L1 that are not in L2 and put them in NewL, while Last stores the last member in L1 that was parsed.
EDIT2: no -> are allowed (this is howmework). If someone could show me how to express if then else in prolog, that could be great.
In short: !/0 applies at the predicate level: here you'd want it to apply to some block level where blocks would be delimited by ( and ). This notion of cut applied to blocks does not exist in Prolog. A cut will erase all encountered choice points up until its location in a predicate.
And instead of writing your code with a lot of (;)/2 usage, consider introducing new clauses instead, for readability (precisely because we do not like parenthesis and figuring out (;)/2 and (,)/2 priorities):
c :- A; B.
can be written
c :- A.
c :- B.
It will quite often be better this way. Better to produce the code easily, better to maintain it, to read it and to expand it.
I didn't look at your predicate in depth or anything, just wanted to mention those two things.
I suspect that "green cut" of yours is not green at all; you have
( A ; B ), !
so on exit from (A ; B) the first time, if A succeeded, B won't be tried anymore - that is what the cut ! is saying here: don't try any more.
If you want B to be tried too, remove the cut !.
If-then-else is:
ifte(A,B,C):- A, B.
ifte(A,B,C):- \+A, C.
We can spare us a not by using a cut,
ifte(A,B,C):- A, !, B.
ifte(A,B,C):- C.
About your code: we express and then with comma: A,B. To output the Last it's easiest to use a working predicate, with additional argument, "seen-last"; and in the base case finally the last seen and the output would be unified.

Resources