I'm trying to write some rule in prolog language to change singular form to plural form and want to support to write the rule.
I assume you want to pluralize English words. One approach is to have a general rule and also some specific rules for special cases.
% special cases
pluralize(deer, deer).
pluralize(mouse, mice).
pluralize(antenna, antennae).
% general rule
pluralize(Singular, Plural) :- atom_concat(Singular, s, Plural).
This seems to be OK for some words:
?- pluralize(coin, X).
X = coins.
?- pluralize(date, X).
X = dates.
But some words seem to trip it up:
?- pluralize(fox, X).
X = foxs.
You could probably make the rule more intelligent. This is where I'd start.
list_member(X,[X|_]).
list_member(X,[_|TALL]):-list_member(X,TALL).
isVowels(A):-list_member(A,[a, e, i, o, u]),!.
isConsonants(A):-list_member(A,[b, c, d, f, g, h, j, k, l, m, n, p, q, r, s, t, v, x, w,y,z]),!.
word:- write('Enter the word you want to know weather it followed by a an or the:.'),read(X),nl,
plular(X):-((isVowels(sub_atom(X, _, 1, 0, C)))->(write('Plular form of '),write(X),write(' is '),write(X),write('s'));(write('Plular form of '),write(X),write(' is '),write(X),write('es'))).
You can have a look on this book "Natural Language Processing for PROLOG Programmers" (Page 262-263) that describes some rules for changing singular form of a word to plural. I have written a simple program that works for nouns. I hope it helps.
morphology(W, Wo):-
(sub_atom(W,_, 2, 0, C), (C == sh; C = ch));
(sub_atom(W,_,1,0,P), (P == s; P == z; P == x)) ->
atom_concat(W,es,Wo) ;
(sub_atom(W,Q,1,0,L), (L == y)) ->
sub_atom(W,_,Q,1,L1), atom_concat(L1,ies,Wo) ;
atom_concat(W,s,Wo).
? morphology('Age', S).
S = 'Ages'.
? morphology(student, S).
S = students.
Related
I'm working on a theory in which there is a relation C defined as
Parameter Entity: Set.
Parameter C : Entity -> Entity -> Entity -> Prop.
The relation C is a relation of composition of some entities. Instead of C z x y, I want to be able to write x o y = z. So I have two questions:
I think I should define a "function" (the word is perhaps not the right one) named fC that takes x and y and returns z. This way, I could use it in the Notation. But I don't know how to define this "function". Is it possible?
I find that I can use the command Notation to define an operator. Something like Notation "x o y" := fC x y.. Is this the good way to do it?
I tried Notation "x o y" := exists u, C u x y. but it didn't work. Is there a way to do what I want to do?
Unless your relation C has the property that, given x and y, there is a unique z such that C z x y, you cannot view it as representing a full-fledged function the way you suggest. This is why the notion of a relation is needed in that case.
As for defining a notation for the relation property, you can use:
Notation "x 'o y" := (exists u, C u x y) (at level 10).
Note the ' before the o to help the parser handle the notation and the parentheses after the := sign. The level can be changed to suit your parsing preferences.
If you define x 'o y as a proposition, you will lose the intuition of o being a binary operation on Entity (i.e x o y should have type Entity).
You may write some variation like
Notation "x 'o y '= z" := (unique (fun t => C t x y)) (at level 10).
Otherwise, If your relation satisfies:
Hypothesis C_fun: forall x y, {z : Entity | unique (fun t => C t x y) z}.
then you may define:
Notation "x 'o y" := (proj1_sig (C_fun x y)) (at level 10).
Check fun a b: Entity => a 'o b.
Otherwise (if you have only have a weaker version of C_fun, with existsinstead of sig) and accept to use classical logic and axioms), you may use the Epsilon operator
https://coq.inria.fr/distrib/current/stdlib/Coq.Logic.ClassicalEpsilon.html
For a project I'm coding group theory through Coq, obviously associatvity of 3 elements is a given, however I'm struggling to prove it holds for a string of length n. That is, (x1 * ... * xn) is always the same regardless of how many brackets are in there, or there placement.
The relevant group code is
Structure group :=
{
e : G;
Op : G -> G -> G;
Inv : G -> G;
Associativity : forall (x y z : G), Op x (Op y z) = Op (Op x y) z;
LeftInverse : forall (x : G), Op (Inv x) x = e;
LeftIdentity : forall (x : G), Op e x = x;
}.
It's not the proof itself I have the issue with but how to code it. I can see at the very least I'll need a further function that allows me to operate on strings rather than just elements, but i've no idea how to get started. Any pointers?
Operating on strings directly is certainly possible, but cumbersome. When reasoning about languages, it is much more convenient to use abstract syntax trees instead. For your statement, we only want to consider combinations of elements with some binary operation, so a binary tree suffices:
Inductive tree T :=
| Leaf : T -> tree T
| Node : tree T -> tree T -> tree T.
For concreteness, I'll only consider the natural numbers under addition, but this generalizes to any other monoid (and thus any other group). We can write a function that sums all the elements of a tree:
Fixpoint sum_tree t : nat :=
match t with
| Leaf n => n
| Node t1 t2 => sum_tree t1 + sum_tree t2
end.
We can also write a function that flattens the tree, collecting all of its elements in a list
Fixpoint elements {T} (t : tree T) : list T :=
match t with
| Leaf x => [x]
| Node t1 t2 => elements t1 ++ elements t2
end.
With these ingredients, we can formulate the statement that you were looking for: if two trees (that is, two ways of putting parenthesis in an expression) have the same sequences of elements, then they must add up to the same number.
Lemma eq_sum_tree t1 t2 :
elements t1 = elements t2 -> sum_tree t1 = sum_tree t2.
I'll leave the proof of this statement to you. ;)
I have a string a and on comparison with string b, if equals has an string c, else has string x. I know in the hypothesis that fun x <= fun c. How do I prove this below statement? fun is some function which takes in string and returns nat.
fun (if a == b then c else x) <= S (fun c)
The logic seems obvious but I am unable to split the if statements in coq. Any help would be appreciated.
Thanks!
Let me complement Yves answer pointing out to a general "view" pattern that works well in many situations were case analysis is needed. I will use the built-in support in math-comp but the technique is not specific to it.
Let's assume your initial goal:
From mathcomp Require Import all_ssreflect.
Variables (T : eqType) (a b : T).
Lemma u : (if a == b then 0 else 1) = 2.
Proof.
now, you could use case_eq + simpl to arrive to next step; however, you can also match using more specialized "view" lemmas. For example, you could use ifP:
ifP : forall (A : Type) (b : bool) (vT vF : A),
if_spec b vT vF (b = false) b (if b then vT else vF)
where if_spec is:
Inductive if_spec (A : Type) (b : bool) (vT vF : A) (not_b : Prop) : bool -> A -> Set :=
IfSpecTrue : b -> if_spec b vT vF not_b true vT
| IfSpecFalse : not_b -> if_spec b vT vF not_b false vF
That looks a bit confusing, the important bit is the parameters to the type family bool -> A -> Set. The first exercise is "prove the ifP lemma!".
Indeed, if we use ifP in our proof, we get:
case: ifP.
Goal 1: (a == b) = true -> 0 = 2
Goal 2: (a == b) = false -> 1 = 2
Note that we didn't have to specify anything! Indeed, lemmas of the form { A
} + { B } are just special cases of this view pattern. This trick works in many other situations, for example, you can also use eqP, which has a spec relating the boolean equality with the propositional one. If you do:
case: eqP.
you'll get:
Goal 1: a = b -> 0 = 2
Goal 2: a <> b -> 1 = 2
which is very convenient. In fact, eqP is basically a generic version of the type_dec principle.
If you can write an if-then-else statement, it means that the test expression a == b is in a type with two constructors (like bool) or (sumbool). I will first assume the type is bool. In that case, the best approach during a proof is to enter the following command.
case_eq (a == b); intros hyp_ab.
This will generate two goals. In the first one, you will have an hypothesis
hyp_ab : a == b = true
that asserts that the test succeeds and the goal conclusion has the following shape (the if-then-else is replaced by the then branch):
fun c <= S (fun c)
In the second goal, you will have an hypothesis
hyp_ab : a == b = false
and the goal conclusion has the following shape (the if-then-else is replaced by the else branch).
fun x <= S (fun c)
You should be able to carry on from there.
On the other hand, the String library from Coq has a function string_dec with return type {a = b}+{a <> b}. If your notation a == b is a pretty notation for string_dec a b, it is better to use the following tactic:
destruct (a == b) as [hyp_ab | hyp_ab].
The behavior will be quite close to what I described above, only easier to use.
Intuitively, when you reason on an if-then-else statement, you use a command like case_eq, destruct, or case that leads you to studying separately the two executions paths, remember in an hypothesis why you took each of these executions paths.
Motivation: I am attempting to study category theory while creating a Coq formalization of the ideas I find in whatever textbook I follow. In order to make this formalization as simple as possible, I figured I should identify objects with their identity arrow, so a category can be reduced to a set (class, type) of arrows X with a source mapping s:X->X, target mapping t:X->X, and composition mapping product : X -> X -> option X which is a partial mapping defined for t f = s g. Obviously the structure (X,s,t,product) should follow various properties. For the sake of clarity, I am spelling out the formalization I chose below, but there is no need to follow it I think in order to read my question:
Record Category {A:Type} : Type := category
{ source : A -> A
; target : A -> A
; product: A -> A -> option A
; proof_of_ss : forall f:A, source (source f) = source f
; proof_of_ts : forall f:A, target (source f) = source f
; proof_of_tt : forall f:A, target (target f) = target f
; proof_of_st : forall f:A, source (target f) = target f
; proof_of_dom: forall f g:A, target f = source g <-> product f g <> None
; proof_of_src: forall f g h:A, product f g = Some h -> source h = source f
; proof_of_tgt: forall f g h:A, product f g = Some h -> target h = target g
; proof_of_idl: forall a f:A,
a = source a ->
a = target a ->
a = source f ->
product a f = Some f
; proof_of_idr: forall a f:A,
a = source a ->
a = target a ->
a = target f ->
product f a = Some f
; proof_of_asc:
forall f g h fg gh:A,
product f g = Some fg ->
product g h = Some gh ->
product fg h = product f gh
}
.
I have no idea how practical this is and how far it will take me. I see this as an opportunity to learn category theory and Coq at the same time.
Problem: My first objective was to create a 'Category' which would resemble as much as possible the category Set. In a set theoretic framework, I would probably consider the class of triplets (a,b,f) where f is a map with domain a and range a subset of b. With this in mind I tried:
Record Arrow : Type := arrow
{ dom : Type
; cod : Type
; arr : dom -> cod
}
.
So that Arrow becomes my base type on which I could attempt building a structure of category. I start embedding Type into Arrow:
Definition id (a : Type) : Arrow := arrow a a (fun x => x).
which allows me to define the source and target mappings:
Definition domain (f:Arrow) : Arrow := id (dom f).
Definition codomain (f:Arrow) : Arrow := id (cod f).
Then I move on to defining a composition on Arrow:
Definition compose (f g: Arrow) : option Arrow :=
match f with
| arrow a b f' =>
match g with
| arrow b' c g' =>
match b with
| b' => Some (arrow a c (fun x => (g' (f' x))))
| _ => None
end
end
end.
However, this code is illegal as I get the error:
The term "f' x" has type "b" while it is expected to have type "b'".
Question: I have the feeling I am not going to get away with this, My using Type naively would take me to some sort of Russel paradox which Coq will not allow me to do. However, just in case, is there a way to define compose on Arrow?
Your encoding does not work in plain Coq because of the constructive nature of the theory: it is not possible to compare two sets for equality. If you absolutely want to follow this approach, Daniel's comment sketches a solution: you need to assume a strong classical principle to be able to check whether the endpoints of two arrows match, and then manipulate an equality proof to make Coq accept the definition.
Another approach is to have separate types for arrows and objects, and use type dependency to express the compatibility requirement on arrow endpoints. This definition requires only three axioms, and considerably simplifies the construction of categories:
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Record category : Type := Category {
obj : Type;
hom : obj -> obj -> Type;
id : forall {X}, hom X X;
comp : forall X Y Z, hom X Y -> hom Y Z -> hom X Z;
(* Axioms *)
idL : forall X Y (f : hom X Y), comp id f = f;
idR : forall X Y (f : hom X Y), comp f id = f;
assoc : forall X Y Z W
(f : hom X Y) (g : hom Y Z) (h : hom Z W),
comp f (comp g h) = comp (comp f g) h
}.
We can now define the category of sets and ask Coq to automatically prove the axioms for us.
Require Import Coq.Program.Tactics.
Program Definition Sets : category := {|
obj := Type;
hom X Y := X -> Y;
id X := fun x => x;
comp X Y Z f g := fun x => g (f x)
|}.
(This does not lead to any circularity paradoxes, because of Coq's universe mechanism: Coq understands that the Type used in this definition is actually smaller than the one used to define category.)
This encoding is sometimes inconvenient due to the lack of extensionality in Coq's theory, because it prevents certain axioms from holding. Consider the category of groups, for example, where the morphisms are functions that commute with the group operations. A reasonable definition for these morphisms could be as follows (assuming that there is some type group representing groups, with * denotes multiplication and 1 denotes the neutral element).
Record group_morphism (X Y : group) : Type := {
mor : X -> Y;
mor_1 : mor 1 = 1;
mor_m : forall x1 x2, mor (x1 * x2) = mor x1 * mor x2
}.
The problem is that the properties mor_1 and mor_m interfere with the notion of equality for elements of group_morphism, making the proofs for associativity and identity that worked for Sets break. There are two solutions:
Adopt extra axioms into the theory so that the required properties still go through. In the above example, you would need proof irrelevance:
proof_irrelevance : forall (P : Prop) (p q : P), p = q.
Change the category axioms so that the identities are valid up to some equivalence relation specific to that category, instead of the plain Coq equality. This approach is followed here, for example.
This is a follow-up on Isabelle's Code generation: Abstraction lemmas for containers?:
I want to generate code for the_question in the following theory:
theory Scratch imports Main begin
typedef small = "{x::nat. x < 10}" morphisms to_nat small
by (rule exI[where x = 0], simp)
code_datatype small
lemma [code abstype]: "small (to_nat x) = x" by (rule to_nat_inverse)
definition a_pred :: "small ⇒ bool"
where "a_pred = undefined"
definition "smaller j = [small i . i <- [0 ..< to_nat j]]"
definition "the_question j = (∀i ∈ set (smaller j). a_pred j)"
The problem is that the equation for smaller is not suitable for code generation, as it mentions the abstraction function small.
Now according to Andreas’ answer to my last question and the paper on data refinement, the next step is to introduce a type for sets of small numbers, and create a definition for smaller in that type:
typedef small_list = "{l. ∀x∈ set l. (x::nat) < 10}" by (rule exI[where x = "[]"], auto)
code_datatype Abs_small_list
lemma [code abstype]: "Abs_small_list (Rep_small_list x) = x" by (rule Rep_small_list_inverse)
definition "smaller' j = Abs_small_list [ i . i <- [0 ..< to_nat j]]"
lemma smaller'_code[code abstract]: "Rep_small_list (smaller' j) = [ i . i <- [0 ..< to_nat j]]"
unfolding smaller'_def
by (rule Abs_small_list_inverse, cases j, auto elim: less_trans simp add: small_inverse)
Now smaller' is executable. From what I understand I need to redefine operations on small list as operations on small_list:
definition "small_list_all P l = list_all P (map small (Rep_small_list l))"
lemma[code]: "the_question j = small_list_all a_pred (smaller' j)"
unfolding small_list_all_def the_question_def smaller'_code smaller_def Ball_set by simp
I can define a good looking code equation for the_question. But the definition of small_list_all is not suitable for code generation, as it mentions the abstraction morphismsmall. How do I make small_list_all executable?
(Note that I cannot unfold the code equation of a_pred, as the problem actually occurs in the code equation of the actually recursive a_pred. Also, I’d like to avoid hacks that involve re-checking the invariant at runtime.)
I don't have a good solution to the general problem, but here's an idea that will let you generate code for the_question in this particular case.
First, define a function predecessor :: "small ⇒ small with an abstract code equation (possibly using lift_definition from λn::nat. n - 1).
Now you can prove a new code equation for smaller whose rhs uses if-then-else, predecessor and normal list operations:
lemma smaller_code [code]:
"smaller j = (if to_nat j = 0 then []
else let k = predecessor j in smaller k # [k])"
(More efficient implementations are of course possible if you're willing to define an auxiliary function.)
Code generation should now work for smaller, since this code equation doesn't use function small.
The short answer is no, it does not work.
The long answer is that there are often workarounds possible. One is shown by Brian in his answer. The general idea seems to be
Separate the function that has the abstract type in covariant positions besides the final return value (i.e. higher order functions or functions returning containers of abstract values) into multiple helper functions so that abstract values are only constructed as a single return value of one of the helper function.
In Brian’s example, this function is predecessor. Or, as another simple example, assume a function
definition smallPrime :: "nat ⇒ small option"
where "smallPrime n = (if n ∈ {2,3,5,7} then Some (small n) else None)"
This definition is not a valid code equation, due to the occurrence of small. But this derives one:
definition smallPrimeHelper :: "nat ⇒ small"
where "smallPrimeHelper n = (if n ∈ {2,3,5,7} then small n else small 0)"
lemma [code abstract]: "to_nat (smallPrimeHelper n) = (if n ∈ {2,3,5,7} then n else 0)"
by (auto simp add: smallPrimeHelper_def intro: small_inverse)
lemma [code_unfold]: "smallPrime n = (if n ∈ {2,3,5,7} then Some (smallPrimeHelper n) else None)"
unfolding smallPrime_def smallPrimeHelper_def by simp
If one wants to avoid the redundant calculation of the predicate (which might be more complex than just ∈ {2,3,5,7}, one can make the return type of the helper smarter by introducing an abstract view, i.e. a type that contains both the result of the computation, and the information needed to construct the abstract type from it:
typedef smallPrime_view = "{(x::nat, b::bool). x < 10 ∧ b = (x ∈ {2,3,5,7})}"
by (rule exI[where x = "(2, True)"], auto)
setup_lifting type_definition_small
setup_lifting type_definition_smallPrime_view
For the view we have a function building it and accessors that take the result apart, with some lemmas about them:
lift_definition smallPrimeHelper' :: "nat ⇒ smallPrime_view"
is "λ n. if n ∈ {2,3,5,7} then (n, True) else (0, False)" by simp
lift_definition smallPrimeView_pred :: "smallPrime_view ⇒ bool"
is "λ spv :: (nat × bool) . snd spv" by auto
lift_definition smallPrimeView_small :: "smallPrime_view ⇒ small"
is "λ spv :: (nat × bool) . fst spv" by auto
lemma [simp]: "smallPrimeView_pred (smallPrimeHelper' n) ⟷ (n ∈ {2,3,5,7})"
by transfer simp
lemma [simp]: "n ∈ {2,3,5,7} ⟹ to_nat (smallPrimeView_small (smallPrimeHelper' n)) = n"
by transfer auto
lemma [simp]: "n ∈ {2,3,5,7} ⟹ smallPrimeView_small (smallPrimeHelper' n) = small n"
by (auto intro: iffD1[OF to_nat_inject] simp add: small_inverse)
With that we can derive a code equation that does the check only once:
lemma [code]: "smallPrime n =
(let spv = smallPrimeHelper' n in
(if smallPrimeView_pred spv
then Some (smallPrimeView_small spv)
else None))"
by (auto simp add: smallPrime_def Let_def)