First Order Logic translation - math

Use the following definitions to represent English statements as first-order formulas.
Define:
● 𝐢 - is a set of companies
● 𝐼 - is a set of investors
● 𝐼𝐢𝑁 = {(𝑖, 𝑐, 𝑛) | (𝑖, 𝑐, 𝑛) ∈ 𝐼 Γ— 𝐢 Γ— 𝑁 ∧ π‘–π‘›π‘£π‘’π‘ π‘‘π‘œπ‘Ÿ 𝑖 β„Žπ‘œπ‘™π‘‘π‘  𝑛 π‘ β„Žπ‘Žπ‘Ÿπ‘’π‘  π‘œπ‘“ π‘π‘œπ‘šπ‘π‘Žπ‘›π‘¦ 𝑐}-
investments
● 𝑃(π‘₯, 𝑖, 𝑐, 𝑛) - investment x describes investor i holding more than n shares of company c
Represent:
"Each company has at least one investor holding more than 100 of its shares"

I had a similar problem and came up short. The way I approached it was:
βˆ€x ∈ C.
βˆƒy ∈ I. (so far)
Unfortunately the ICN and P(x,i,c,n) part is tripping me up, especially regarding n>100. I hope that I'm correct so far; hopefully someone with more knowledge can build off of/correct what I have.

I have tried to solve this and came with this solution:
βˆ€c∈C. βˆƒi∈I. βˆƒx∈ICN. P(x,i,c,100)
Can someone confirm if this is the correct solution?

Related

How to have full control over substitution in Isabelle

In Isabelle I find myself often using
apply(subst xx)
apply(rule subst)
apply(subst_tac xx)
and similar command but often it is a hit or miss. Is there any resources on how to guide the
term unification and how to precisely specify the terms that should be substituted for?
For example if there are multiple ways to perform unification, how can I disambiguate?
If I have multiple equalities among the premises, how can I tell Isabelle which one of them to use? I spend way too much time wrestling with such seemingly simple problems.
This book https://www21.in.tum.de/~nipkow/LNCS2283/ has a chapter dedicated to substitution but it's far too short, only covers erule ssubst and doesn't really answer my questions.
To give some examples, this is ssubst
lemma ssubst: "t = s ⟹ P s ⟹ P t"
by (drule sym) (erule subst)
but what about
lemma arg_cong: "x = y ⟹ f x = f y"
by (iprover intro: refl elim: subst)
How can I do erule_tac arg_cong and specify exactly the desired f, x and y? Anything I tried resulted in Failed to apply proof method which is not a particularly enlightening error message.
As I recall, a more elaborate substitution method is available, in particular for restricting substitution to certain contexts. But to answer your question properly it's essential to know what sort of assertions you are trying to prove. If you are working with short expressions (up to a couple of lines long), then it's much better to guide the series of transformations using equational reasoning, via also and finally. (See Programming and Proving in Isabelle/HOL, 4.2.2 Chains of (In)Equations.) Then at the cost of writing out these expressions, you'll often find that you can prove each step automatically, without detailed substitutions, and you can follow your reasoning.
Also note that if your expressions are long because they contain large, repeated subexpressions, you can introduce abbreviations using define. You will then not only have shorter and clearer proofs, but you will find that automation will perform much better.
The other situation is when you are working with verification conditions dozens of lines long, or even longer. In that case it is worth looking for more advanced substitution packages.

Refining a definition in Isabelle

I have the following definition in Isabelle (for details see here):
definition gluing :: "(((real Γ— real) Γ— bit) Γ— (real Γ— real) Γ— bit) set" where
"gluing = {(((x0,y0),l),((x1,y1),j)).
((x0,y0) ∈ e_circ ∧ (x1,y1) = Ο„ (x0,y0) ∧ j = l+1) ∨
(x0 = x1 ∧ y0 = y1 ∧ l = j)}"
Now, this gluing is supposed to be defining an equivalence relation over the set:
e_aff Γ— (range Bit)
So I would like to refine the type:
(real Γ— real) Γ— bit
to this. If I do it directly on the definition of gluing I get:
Undefined type name: "e_aff"βŒ‚
But if I instead try to do it through a type definition:
typedef e_aff_t = "e_aff"
I get:
Illegal variables in representing set: "d"
The error(s) above occurred in typedef "e_aff_t"
I think this comes from the internal definition of e_aff.
How should I solve it?
I will provide several remarks. If these are not sufficient, please feel free to ask further questions and I will try to do my best to reply.
But if I instead try to do it through a type definition:
typedef e_aff_t = "e_aff"
I get:
Illegal variables in representing set: "d" The error(s) above occurred
in typedef "e_aff_t"
This happens because e_aff depends on fixed variables. To the best of my knowledge, this is not accepted by the logic at the moment (with the exception of limited support through Local Typedef Rule from Types-To-Sets):
typedef Ξ± k = S requires S to be a closed term, k to be a
fresh type constructor and all type variables in S need to be among the
variables in α. In your case, S is not a closed term. There are many valuable resources that explain this in detail and many of them are referenced in the PhD thesis of Ondřej Kunčar.
Plausible solutions
The possible options are presented in the order of my personal preference, given what I know about your application. However, keep in mind, that this may not be an exhaustive list, given my own limited experience, and, also, I know very little about your end goal.
Set-based quotients
I believe that the simplest way to express that gluing is an equivalence relation on e_aff Γ— UNIV::bit is
definition qs where "qs = (e_aff Γ— (range Bit)) // gluing"
lemma "equiv (e_aff Γ— (range Bit)) gluing"
sorry
Once this is done, the theory Equiv_Relations (among others) provides many useful theorems for dealing with set-based quotients.
Types-To-Sets
You also have the option to use Local Typedef Rule from Types-To-Sets to create a context with the quotient_type based on fixed variables. However, you would still need to convert the type-based theorems to their set-based counterparts before you can use them in any application (the conversion is automated). If you are interested, I can provide more details and an example. However, I believe, for your application, this is hardly more superior than dealing with the set-based theorems directly.
quotient_type
If, for any reason, you still insist on using the type-based approach, then, I guess, you could try restating the theory in a way such that e_aff does not depend on fixed variables. For this, you can use Hilbert choice, e.g. definition c where "c = (SOME c::real. True)", etc... However, I do not believe that this is a standard practice and would be encouraged.

Prolog Accumulators. Are they really a "different" concept?

I am learning Prolog under my Artificial Intelligence Lab, from the source Learn Prolog Now!.
In the 5th Chapter we come to learn about Accumulators. And as an example, these two code snippets are given.
To Find the Length of a List
without accumulators:
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
with accumulators:
accLen([_|T],A,L) :- Anew is A+1, accLen(T,Anew,L).
accLen([],A,A).
I am unable to understand, how the two snippets are conceptually different? What exactly an accumulator is doing different? And what are the benefits?
Accumulators sound like intermediate variables. (Correct me if I am wrong.) And I had already used them in my programs up till now, so is it really that big a concept?
When you give something a name, it suddenly becomes more real than it used to be. Discussing something can now be done by simply using the name of the concept. Without getting any more philosophical, no, there is nothing special about accumulators, but they are useful.
In practice, going through a list without an accumulator:
foo([]).
foo([H|T]) :-
foo(T).
The head of the list is left behind, and cannot be accessed by the recursive call. At each level of recursion you only see what is left of the list.
Using an accumulator:
bar([], _Acc).
bar([H|T], Acc) :-
bar(T, [H|Acc]).
At every recursive step, you have the remaining list and all the elements you have gone through. In your len/3 example, you only keep the count, not the actual elements, as this is all you need.
Some predicates (like len/3) can be made tail-recursive with accumulators: you don't need to wait for the end of your input (exhaust all elements of the list) to do the actual work, instead doing it incrementally as you get the input. Prolog doesn't have to leave values on the stack and can do tail-call optimization for you.
Search algorithms that need to know the "path so far" (or any algorithm that needs to have a state) use a more general form of the same technique, by providing an "intermediate result" to the recursive call. A run-length encoder, for example, could be defined as:
rle([], []).
rle([First|Rest],Encoded):-
rle_1(Rest, First, 1, Encoded).
rle_1([], Last, N, [Last-N]).
rle_1([H|T], Prev, N, Encoded) :-
( dif(H, Prev)
-> Encoded = [Prev-N|Rest],
rle_1(T, H, 1, Rest)
; succ(N, N1),
rle_1(T, H, N1, Encoded)
).
Hope that helps.
TL;DR: yes, they are.
Imagine you are to go from a city A on the left to a city B on the right, and you want to know the distance between the two in advance. How are you to achieve this?
A mathematician in such a position employs magic known as structural recursion. He says to himself, what if I'll send my own copy one step closer towards the city B, and ask it of its distance to the city? I will then add 1 to its result, after receiving it from my copy, since I have sent it one step closer towards the city, and will know my answer without having moved an inch! Of course if I am already at the city gates, I won't send any copies of me anywhere since I'll know that the distance is 0 - without having moved an inch!
And how do I know that my copy-of-me will succeed? Simply because he will follow the same exact rules, while starting from a point closer to our destination. Whatever value my answer will be, his will be one less, and only a finite number of copies of us will be called into action - because the distance between the cities is finite. So the total operation is certain to complete in a finite amount of time and I will get my answer. Because getting your answer after an infinite time has passed, is not getting it at all - ever.
And now, having found out his answer in advance, our cautious magician mathematician is ready to embark on his safe (now!) journey.
But that of course wasn't magic at all - it's all being a dirty trick! He didn't find out the answer in advance out of thin air - he has sent out the whole stack of others to find it for him. The grueling work had to be done after all, he just pretended not to be aware of it. The distance was traveled. Moreover, the distance back had to be traveled too, for each copy to tell their result to their master, the result being actually created on the way back from the destination. All this before our fake magician had ever started walking himself. How's that for a team effort. For him it could seem like a sweet deal. But overall...
So that's how the magician mathematician thinks. But his dual the brave traveler just goes on a journey, and counts his steps along the way, adding 1 to the current steps counter on each step, before the rest of his actual journey. There's no pretense anymore. The journey may be finite, or it may be infinite - he has no way of knowing upfront. But at each point along his route, and hence when ⁄ if he arrives at the city B gates too, he will know his distance traveled so far. And he certainly won't have to go back all the way to the beginning of the road to tell himself the result.
And that's the difference between the structural recursion of the first, and tail recursion with accumulator ⁄ tail recursion modulo cons ⁄ corecursion employed by the second. The knowledge of the first is built on the way back from the goal; of the second - on the way forth from the starting point, towards the goal. The journey is the destination.
see also:
Technical Report TR19: Unwinding Structured Recursions into Iterations. Daniel P. Friedman and David S. Wise (Dec 1974).
What are the practical implications of all this, you ask? Why, imagine our friend the magician mathematician needs to boil some eggs. He has a pot; a faucet; a hot plate; and some eggs. What is he to do?
Well, it's easy - he'll just put eggs into the pot, add some water from the faucet into it and will put it on the hot plate.
And what if he's already given a pot with eggs and water in it? Why, it's even easier to him - he'll just take the eggs out, pour out the water, and will end up with the problem he already knows how to solve! Pure magic, isn't it!
Before we laugh at the poor chap, we mustn't forget the tale of the centipede. Sometimes ignorance is bliss. But when the required knowledge is simple and "one-dimensional" like the distance here, it'd be a crime to pretend to have no memory at all.
accumulators are intermediate variables, and are an important (read basic) topic in Prolog because allow reversing the information flow of some fundamental algorithm, with important consequences for the efficiency of the program.
Take reversing a list as example
nrev([],[]).
nrev([H|T], R) :- nrev(T, S), append(S, [H], R).
rev(L, R) :- rev(L, [], R).
rev([], R, R).
rev([H|T], C, R) :- rev(T, [H|C], R).
nrev/2 (naive reverse) it's O(N^2), where N is list length, while rev/2 it's O(N).

CLSR chip testing problem

Finding ONE good VLSI chip in a population of good and bad ones, by using the
pair test.
Chip A Chip B Conclusion
------- ------- ----------
B is good A is good both are good or both are bad
B is good A is bad at least one is bad
B is bad A is good at least one is bad
B is bad A is bad at least one is bad
Assumption : number of goods > number of bads
We can solve this in O(n) time complexity by splitting the population in half
every time and collecting one element of the GOOD, GOOD pair.
T(n) = T(n/2) + n/2
But to collect the pairs we need n/2 memory separately.
Can we do this in-place without using extra memory ??
The algorithm is based on the question, "can we remove this chip?" So, for each chip to be removed, we simply erase it from our linked list, in place (or rather, no place at all).

Friends selection algorithm

In a .net project we have a group of 200 people of two types, lets say x and y, who need to be separated into groups of 7 or 8.
We have a web page where the people write other members they want to be in a group with. Each person builds a list of wanted members.
After this, there should be an algorithm to build the 7-8 member groups considering the peoples ratings, and the following condition: each group has at least 2 people of each type (x/y).
I'm pretty sure there must be a well known algorithm similar to this but didn't find one. Anyone knows how to do it?
this problem smells NP-Hard, so I suggest using Artificial Intelligence tools.
A possible approach is steepest ascent hill climbing [SAHC]
first, we will define our utility function (let it be u) as mentioned in the comments to the question. [sum of friends in group for each user]. let's define u(illegal) = -1 for illegal solution.
next,we define our 'world': S is the group of all possible solutions].
for each solution in S we define:
next(s)={all possibilities moving one person to a different group}
all we have to do now is run SAHC with random restarts:
1. best<- -INFINITY
2. while there is more time
3. choose a random legal solution
4. NEXT <- next(s)
5. if max{ U(NEXT) } < u(s): //s is the top of the hill
5.1. if u(s) > best: best <- u(s) //if s is better then the previous result - store it.
5.2. go to 2. //restart the hill climbing from a different random point.
6. else:
6.1. s <- max{ NEXT } //climb on the steepest hill.
6.2. goto 4.
7. return best //when out of time, return the best solution found so far.
It is anytime algorithm, meaning it will get a better result as you give it more time to run, and eventually [at time infinity] it will find the optimal result.

Resources