I need some help and guidelines.
I have the following relation: R = {A, B, C, D, E, F} and the set of functional dependencies
F = {
{AB -> C};
{A -> D};
{D -> AE};
{E -> F};
}
What is the primary key for R ?
If i apply inference rules i get these additional Function dependencies:
D -> A
D -> E
D -> F
D -> AEF
A -> E
A -> F
A -> DEF
How do I continue?
There is a well known algorithm to do this. I don't remember it, but the excercise seems to be simple enough not to use it.
I think this is all about transitivity:
CurrentKey = {A, B, C, D, E, F}
You know D determines E and E determines F. Hence, D determines F by transitivity. As F doesn't determine anything, we can remove it and as E can be obtained from D we can remove it as well:
CurrentKey = {A, B, C, D}
As AB determines C and C doesn't determine anything we know it can't be part of the key, so we remove it:
CurrentKey = {A, B, D}
Finally we know A determines D so we can remove the latter from the key:
CurrentKey = {A, B}
If once you have this possible key, you can recreate all functional dependencies it is a possible key.
PS: If you happen to have the algorithm handy, please post it as I'd be glad to re-learn that :)
Algorithm: Key computation (call with x = ∅)
procedure key(x;A;F)
foreach ! B 2 F do
if x and B 2 x and B ̸2 then
return; /* x not minimal */
fi
od
if x+ = A then
print x; /* found a minimal key x */
else
X any element of A x+;
key(x [ fXg;A;F);
foreach ! X 2 F do
key(x [ ;A;F);
od
fi
Related
I am new to Coq and was wondering what is the difference between the following things:
Class test (f g: nat -> nat) := {
init: f 0 = 0 /\ g 0 = 0;
output: ...another proposition about f and g...;
}.
and
Class test := {
f: nat -> nat;
g: nat -> nat;
init: f 0 = 0 /\ g 0 = 0;
output: ...another proposition about f and g...;
}.
Could anyone provide an explanation ?
The difference between them is referred to as bundling.
Class test (f g: nat -> nat) := {
init: f 0 = 0 /\ g 0 = 0;
output: ...another proposition about f and g...;
}.
is unbundled, and
Class test := {
f: nat -> nat;
g: nat -> nat;
init: f 0 = 0 /\ g 0 = 0;
output: ...another proposition about f and g...;
}.
is bundled.
The advantage of bundling is that you don't need to always provide f and g. The advantage of unbundling is that you can have different instances of the same class sharing the same f and g. If you bundle them, Coq will not be easily convinced that different instances share parameters.
You can read more about this in Type Classes for Mathematics in Type Theory.
To complement Ana’s excellent answer, here is a practical difference:
the unbundled version (call it utest) allows you to write the logical statement utest f g about a specific pair of functions f and g,
whereas the bundled version (call it btest) allows you to state that there exists a pair of functions which satisfies the properties; you can later refer to these functions by the projection names f and g.
So, roughly speaking:
btest is “equivalent” to ∃ f g, utest f g;
utest f' g' is “equivalent” to btest ∧ “the f (resp. g) in the aforementioned proof of btest is equal to f' (resp. g')”.
More formally, here are the equivalences for a minimal example
(in this code, the notation { x : A | B } is a dependent pair type,
i.e. the type of (x, y) where x : A and y : B
and the type B depends on the value x):
(* unbundled: *)
Class utest (x : nat) : Prop := {
uprop : x = 0;
}.
(* bundled: *)
Class btest : Type := {
bx : nat;
bprop : bx = 0;
}.
(* [btest] is equivalent to: *)
Goal { x : nat | utest x } -> btest.
Proof.
intros [x u]. econstructor. exact (#uprop x u).
Qed.
Goal btest -> { x : nat | utest x }.
Proof.
intros b. exists (#bx b). constructor. exact (#bprop b).
Qed.
(* [utest x] is equivalent to: *)
Goal forall x, { b : btest | #bx b = x } -> utest x.
Proof.
intros x [b <-]. constructor. exact (#bprop b).
Qed.
Goal forall x, utest x -> { b : btest | #bx b = x }.
Proof.
intros x u. exists {| bx := x ; bprop := #uprop x u |}. reflexivity.
Qed.
(* NOTE: Here I’ve explicited all implicit arguments; in fact, you
can let Coq infer them, and write just [bx], [bprop], [uprop]
instead of [#bx b], [#bprop b], [#uprop x u]. *)
In this example, we can also observe a difference with respect to computational relevance: utest can live in Prop, because its only member, uprop, is a proposition. On the other hand, I cannot really put btest in Prop, because that would mean that both bx and bprop would live in Prop but bf is computationally relevant. In other words, Coq gives you this warning:
Class btest : Prop := {
bx : nat;
bprop : bx = 0;
}.
(* WARNING:
bx cannot be defined because it is informative and btest is not.
bprop cannot be defined because the projection bx was not defined.
*)
I would like to define a function of the following type
pairEquality :
(a, b : (obj1, obj2))
-> (fst a) = (fst b)
-> (snd a) = (snd b)
-> a = b
but I am a bit at loss with the implementation.
I know I can write
pairEquality' :
a1 = b1
-> a2 = b2
-> (a1, a2) = (b1, b2)
but that doesn't seem to compile where I need to use it (that's another question: what's the big difference between the two functions?)
The first implementation is pretty straight-forward. Once you split the tuples to get pairEquality (a, b) (x, y) prf1 prf2 = ?t and inspect the the hole, you already see, that the compiler infers that prf1 : a = x, prf2: b = y, alas:
pairEquality :
(a, b : (obj1, obj2))
-> (fst a) = (fst b)
-> (snd a) = (snd b)
-> a = b
pairEquality (x, y) (x, y) Refl Refl = Refl
In pairEquality you de-construct the tuples and in pairEquality' you construct the tuples. Latter is usually a better approach, and I guess you can change something in your caller function so it can be used.
I actually find out I can define pairEquality in terms of pairEquality' as
pairEquality :
(a, b : (obj1, obj2))
-> (fst a) = (fst b)
-> (snd a) = (snd b)
-> a = b
pairEquality (a1, a2) (b1, b2) = pairEquality' {a1} {a2} {b1} {b2}
Let's consider the following:
f: Int -> Int -> Int -> Int
f a b c = a + b + c
g: Int -> Int
g x = x * 2
now, I'd like to create a composed function like
f(g(a), g(b), g(c))
how to use << and >> operators to achieve that? Is it even possible to compose multivariadic functions?
how to use << and >> operators to achieve that? Is it even possible to compose multivariadic functions?
Yes, easily:
h = flip flip g << ((<<) (<<)) << ((>>) g) << f << g
h is a <function> : number -> number -> number -> number, which is the same as h a b c = f (g a) (g b) (g c).
I think we don't need to dig deep in the correctness, since it's obvious that the version with arguments is much more readable.
Multivariadic does not really exist in Elm. Best I can suggest is
f : Int -> Int -> Int -> Int
f a b c =
[ a, b, c ] |> List.map ((<|) g) |> List.sum
g : Int -> Int
g x =
x * 2
Note that you had an error in the type signature for g
I somewhat recently asked a question and resolved the issue with a some applications of the rewrite tactic. I then decided to look back at one of my other questions on code review asking for a review of my attempt to formalize Hilbert's (based on Euclid's) geometry.
From the first question, I learned there is a distinction between propositional equality and boolean equality and propositional equality. Looking back at the some of the axioms I wrote for the Hilbert plane, I utilized boolean equality extensively. Although I am not 100% sure, in light of the answer I received, I suspect that I don't want to use boolean equality.
For instance, take this axiom:
-- There exists 3 non-colinear points.
three_non_colinear_pts : (a : point ** b : point ** c : point **
(colinear a b c = False,
(a /= b) = True,
(b /= c) = True,
(a /= c) = True))
I tried rewriting it to not involve the = True:
-- There exists 3 non-colinear points.
three_non_colinear_pts : (a : point ** b : point ** c : point **
(colinear a b c = False,
(a /= b),
(b /= c),
(a /= c)))
All in all I took the code from my question on codereview removed the == and removed = True:
interface Plane line point where
-- Abstract notion for saying three points lie on the same line.
colinear : point -> point -> point -> Bool
coplanar : point -> point -> point -> Bool
contains : line -> point -> Bool
-- Intersection between two lines
intersects_at : line -> line -> point -> Bool
-- If two lines l and m contain a point a, they intersect at that point.
intersection_criterion : (l : line) ->
(m : line) ->
(a : point) ->
(contains l a = True) ->
(contains m a = True) ->
(intersects_at l m a = True)
-- If l and m intersect at a point a, then they both contain a.
intersection_result : (l : line) ->
(m : line) ->
(a : point) ->
(intersects_at l m a = True) ->
(contains l a = True, contains m a = True)
-- For any two distinct points there is a line that contains them.
line_contains_two_points : (a :point) ->
(b : point) ->
(a /= b) ->
(l : line ** (contains l a = True, contains l b = True ))
-- If two points are contained by l and m then l = m
two_pts_define_line : (l : line) ->
(m : line) ->
(a : point) ->
(b : point) ->
(a /= b) ->
contains l a = True ->
contains l b = True ->
contains m a = True ->
contains m b = True ->
(l = m)
same_line_same_pts : (l : line) ->
(m : line) ->
(a : point) ->
(b : point) ->
(l /= m) ->
contains l a = True ->
contains l b = True ->
contains m a = True ->
contains m b = True ->
(a = b)
-- There exists 3 non-colinear points.
three_non_colinear_pts : (a : point ** b : point ** c : point **
(colinear a b c = False,
(a /= b),
(b /= c),
(a /= c)))
-- Any line contains at least two points.
contain_two_pts : (l : line) ->
(a : point ** b : point **
(contains l a = True, contains l b = True))
-- If two lines intersect at a point and they are not identical, that is the o-
-- nly point they intersect at.
intersect_at_most_one_point : Plane line point =>
(l : line) -> (m : line) -> (a : point) -> (b : point) ->
(l /= m) ->
(intersects_at l m a = True) ->
(intersects_at l m b = True) ->
(a = b)
intersect_at_most_one_point l m a b l_not_m int_at_a int_at_b =
same_line_same_pts
l
m
a
b
l_not_m
(fst (intersection_result l m a int_at_a))
(fst (intersection_result l m b int_at_b))
(snd (intersection_result l m a int_at_a))
(snd (intersection_result l m b int_at_b))
This gives the error:
|
1 | interface Plane line point where
| ~~~~~~~~~~~~~~~~
When checking type of Main.line_contains_two_points:
Type mismatch between
Bool (Type of _ /= _)
and
Type (Expected type)
/home/dair/scratch/hilbert.idr:68:29:
|
68 | intersect_at_most_one_point : Plane line point =>
| ^
When checking type of Main.intersect_at_most_one_point:
No such variable Plane
So, it seems that /= works only for boolean. I have been unable to find a "propositional" /= like:
data (/=) : a -> b -> Type where
Does a propositional not equals exist? Or am I wrong about wanting to change from boolean to propositional equality?
The propositional equivalent to the boolean a /= b would be a = b -> Void. Void is a type with no constructors. So whenever you have a contra : Void, something has gone wrong. So a = b -> Void is to understand as: if you have an a = b, there is a contradiction. Usually written as Not (a = b), which is just a shorthand (Not a = a -> Void).
You're right to change to propositional equality. You might even change your boolean properties like contains : line -> point -> Bool to Contains : line -> point -> Type. Subsequently contains l p = True to Contains l p, and contains l p = False to Not (Contains l p).
That's a case of boolean blindness, i.e. with prf : contains l p = True, the only thing we know is that contains l p is True (and the compiler would need to take a look at contains to guess why it is True). On the other hand, with prf : Contains l p you have a constructed proof prf why the proposition Contains l p holds.
I have a function with Type signature
a -> b -> (a, b)
And I have
Maybe a
How can I map such a function such that I can get
(a->b->(a,b)) -> Maybe a -> (Maybe a, b)
You need to slightly change the function definition
g : (a -> b -> (a,b)) -> Maybe a -> b -> (Maybe a, b)
g f ma b =
case ma of
Nothing -> (Nothing, b)
Just a ->
let
r = f a b
in
(Just (first r), second r)