Solution (source code)

= Solution

Use first cousins: the children of the siblings of a recorded parent. This includes cousins through a parent's half-sibling under the convention above. In <Haskell>:

``
cousins :: Database -> Person -> [Person]
cousins db p = unique [q | parent <- parents db p,
                          auntOrUncle <- siblings db parent,
                          q <- children db auntOrUncle, q /= p]
``

Selecting siblings of parents avoids the mistake of returning all people with a common grandparent, which would also return ordinary siblings. The explicit exclusion of `p` is harmless on an ordinary consistent pedigree and prevents a self-result in unusual records. Multiple relationship paths give just one output entry after <duplicate removal>. Thus
$$
\boxed{\operatorname{cousins}(db,p)=
\bigcup_{r\in\operatorname{parents}(db,p)}\ \bigcup_{s\in\operatorname{siblings}(db,r)}
\operatorname{children}(db,s)\setminus\{p\}.}
$$