Here is another use-case I found for riffleo: subsequenceo, a 3-relation 
between two lists and one of their common subsequences. It might also be 
possible to create a* longest *common subsequence relation by adding a 
disequality constraint somewhere.


#lang racket

(include "../../CodeFromTheReasonedSchemer2ndEd/trs2-impl.scm")

(require "riffleo.mk.rkt")

(defrel (subsequenceo l1 l2 s)
  (fresh (x1 x2)
         (riffleo s x1 l1)
         (riffleo s x2 l2)))

#;(run 10 (l1 l2 s) (subsequenceo l1 l2 s))
#;'((()
     ()
     ())

    (()
     (_0 . _1)
     ())
    
    ((_0 . _1)
     (_0 . _1)
     (_0 . _1))
    
    ((_0 . _1)
     ()
     ())

    ((_0 . _1)
     (_2 . _3)
     ())

    ((   _0 . _1)
     (_2 _0 . _1)
     (   _0 . _1))
    
    ((_0)
     (_0 _1 . _2)
     (_0))
    
    ((_0 _1 . _2)
     (   _1 . _2)
     (   _1 . _2))

    ((      _0 . _1)
     (_2 _3 _0 . _1)
     (      _0 . _1))
    
    ((_0    _1 . _2)
     (_0 _3 _1 . _2)
     (_0    _1 . _2)))


#;(run 10 (l1 l2) (subsequenceo l1 l2 '(a b c)))
#;'(((a b c)
     (a b c))
    
    ((   a b c)
     (_0 a b c))

    ((_0 a b c)
     (   a b c))
    
    ((a    b c)
     (a _0 b c))
    
    ((      a b c)
     (_0 _1 a b c))
    
    ((_0 a b c)
     (_1 a b c))
    
    ((a b c)
     (a b c _0 . _1))

    ((a b    c)
     (a b _0 c))
    
    ((a _0 b c)
     (a    b c))
    
    ((   a    b c)
     (_0 a _1 b c)))
On Thursday, December 29, 2022 at 11:25:18 PM UTC-5 Brett Schreiber wrote:

> I found this relation in two more places:
>
> First was in the Wikipedia article on Logic programming, under "Concurrent 
> logic programming". It is written in Prolog as shuffle/3. Here, the 
> relation models the nondeterminism that occurs when two processes run at 
> the same time. It was added in a 2014 revision, and it can still be found 
> in the current version of the article:
>
> https://en.wikipedia.org/w/index.php?title=Logic_programming&diff=prev&oldid=621458003
>
> Second was in this StackOverflow question from 2018, which I found from 
> Googling "prolog shuffle". The question asks how the relation works, and 
> does not give any applications.
>
> https://stackoverflow.com/questions/52211171/how-does-this-prolog-code-really-work-shuffle-two-lists
> On Monday, October 24, 2022 at 2:40:13 PM UTC-4 Brett Schreiber wrote:
>
>> Hi Will!
>>
>> The `split` relation in the code you linked (llmr.scm)  is a very similar 
>> relation on the domain of multisets. Thank you for sharing!
>>
>> Regarding another use of `riffleo`: I have been trying to transform an 
>> undirected graph into a sequence of nonoverlapping bicliques (complete 
>> bipartite subgraphs). This is always possible, since every graph has a 
>> maximum independent edge set (which can be thought of as (1, 1)-bicliques). 
>> This decomposition into bicliques has an application in graph coloring.
>>
>> I have found `riffleo` useful for partitioning the vertices of the graph 
>> into 3 sets: `left`, `right`, and `rest-v`. Then I can check if there is an 
>> edge from every vertex in `left` to every vertex in `right`. Here is the 
>> code for that. Hopefully the implicit relations make sense.
>>
>> (defrel (bicliqueso graph bicliques)
>>   (conde
>>     ((== bicliques '()) (empty-grapho graph))
>>
>>     ((fresh (v e rest-v rest-e rest-g rest-bicliques left right*rest-v 
>> right)
>>       ;; A biclique is a pair of vertex sets
>>       (== bicliques `((,left . ,right) . ,rest-bicliques))
>>       (pairo left)
>>       (pairo right)
>>        
>>       ;; Assume an efficient undirected graph data structure
>>       (verticeso g v)
>>       (verticeso rest-g rest-v)
>>       (edgeso g e)
>>       (edgeso rest-g rest-e)
>>
>> *      ;; partition the vertices into nonempty `left`, nonempty `right`, 
>> and `rest-v`*
>>
>> *      (riffleo left right*rest-v v)      (riffleo right rest-v 
>> right*rest-v)*
>>
>>       ;; check that every vertex in `left` is connected to every vertex 
>> in `right`
>>       (is-bicliqueo left right g)
>>
>>       ;; Keep only the edges which have both vertices in `rest-v`
>>       (filtero e rest-v rest-e)
>>            
>>       (bicliqueso rest-g rest-bicliques)))))
>>
>>
>> This ended up being unfeasible since I could not think of a good data 
>> structure for representing an undirected graph in miniKanren, and I found 
>> it difficult to write `is-bicliqueo`. I ended up porting `riffleo` into 
>> Python as `unriffle`.
>>
>> def unriffle(o: List[T]) -> Iterator[Tuple[List[T], List[T]]:
>>     ...
>>
>> I used that for a while in Python until I figured out a bottom-up way to 
>> find all bicliques by constructing a table all_bicliques_of_size[m][n].
>>
>> TL;DR - `riffleo` can be used to partition a set into n disjoint subsets, 
>> which may be useful for detecting bicliques.
>>
>> Brett
>> On Monday, October 24, 2022 at 1:16:10 PM UTC-4 William Byrd wrote:
>>
>>> Hi Brett!
>>>
>>> I don't recall if I've used `riffleo` before, but I agree that it looks 
>>> useful!
>>>
>>> We may have used something similar in this code:
>>>
>>> https://github.com/webyrd/linear-logic-multiset-rewriting
>>>
>>> What are other examples of uses of `riffleo` that you have encountered?
>>>
>>> Cheers,
>>>
>>> --Will
>>>
>>> On Mon, Oct 24, 2022 at 12:35 PM Brett Schreiber <[email protected]> 
>>> wrote:
>>>
>>>> Hello all,
>>>> I have become very interested in relational programming, and I have 
>>>> enjoyed trying to a variety of search problems in miniKanren. I have found 
>>>> a relation that has been useful to many of these problems.
>>>>
>>>> Consider the relation a * b = o where:
>>>>
>>>>    1. a is a list
>>>>    2. b is another list, and
>>>>    3. o is the result of nondeterministically merging the lists, i.e., 
>>>>    (a * b)
>>>>
>>>> It reminds me of the "riffle" step when shuffling a deck of cards.
>>>> Here is an example:
>>>>
>>>> a = '(    a   b c     d   e     f)
>>>> b = '(1 2   3     4 5   6   7 8  )
>>>> o = '(1 2 a 3 b c 4 5 d 6 e 7 8 f)
>>>>
>>>> Some properties:
>>>>
>>>>    - a * (b * c) = (a * b) * c
>>>>    - |a * b| = |a| + |b|
>>>>    - (a * b) contains a and b as subsequences
>>>>       - which implies if (a * b) is sorted, then a is sorted and b is 
>>>>       sorted
>>>>    - a * b = b * a
>>>>
>>>> Notice that appendo shares all of these properties except the last 
>>>> one. So this is some sort of generalization of appendo.
>>>>
>>>> Here is the relation's definition in miniKanren, where a * b = o is 
>>>> written (riffleo a b o)
>>>>
>>>> (defrel (riffleo a b o)
>>>>     (fresh (car-a cdr-a car-b cdr-b car-o cdr-o)
>>>>         (conde
>>>>             ;; If `a` and `b` are both empty, then the output is empty.
>>>>             ((== a '()) (== b '()) (== o '()))
>>>>             
>>>>             ;; If `a` is non-empty and `b` is empty,
>>>>             ;; then the output is equal to `a`.
>>>>             ((== a `(,car-a . ,cdr-a)) (== b '()) (== o a))
>>>>             
>>>>             ;; If `a` is empty and `b` is non-empty,
>>>>             ;; then the output is equal to `b`.
>>>>             ((== a '()) (== b `(,car-b . ,cdr-b)) (== o b))
>>>>             
>>>>             ;; When both `a` and `b` are non-empty
>>>>             ((== a `(,car-a . ,cdr-a)) (== b `(,car-b . ,cdr-b)) (== o 
>>>> `(,car-o . ,cdr-o))
>>>>                 (conde
>>>>                     ((== car-o car-a) (riffleo cdr-a b cdr-o))
>>>>                     ((== car-o car-b) (riffleo a cdr-b cdr-o)))))))
>>>>                     
>>>> And after applying a correctness-preserving transformation:
>>>>
>>>> (defrel (riffleo a b o)
>>>>     (fresh (car-a cdr-a car-b cdr-b car-o cdr-o *z0 z1*)
>>>>         (conde
>>>>             ;; If `a` and `b` are both empty,
>>>>             ;; then the output is empty.
>>>>             ((== a '()) (== b '()) (== o '()))
>>>>             
>>>>             ;; If `a` is non-empty and `b` is empty,
>>>>             ;; then the output is equal to `a`.
>>>>             ((== a `(,car-a . ,cdr-a)) (== b '()) (== o a))
>>>>             
>>>>             ;; If `a` is empty and `b` is non-empty, then the output is 
>>>> equal to `b`.
>>>>             ((== a '()) (== b `(,car-b . ,cdr-b)) (== o b))
>>>>             
>>>>             ;; When both `a` and `b` are non-empty
>>>>             ((== a `(,car-a . ,cdr-a)) (== b `(,car-b . ,cdr-b)) (== o 
>>>> `(,car-o . ,cdr-o))
>>>>                 
>>>>
>>>>
>>>>
>>>> *(conde                    ((== car-o car-a) (== z0 cdr-a) (== z1 b))  
>>>>                   ((== car-o car-b) (== z0 a) (== z1 cdr-b)))              
>>>>                       (riffleo z0 z1 cdr-o)*))))
>>>>
>>>> I have found riffleo to be useful as a "choose" function when the 
>>>> arguments are considered multisets rather than lists. For example, it 
>>>> makes 
>>>> it easy to write the NP-complete 3-partition problem 
>>>> <https://en.wikipedia.org/wiki/3-partition_problem> as a relation.
>>>>
>>>> (defrel (three-partitiono l partitions sum)
>>>>     (fresh (e0 e1 e2 rest-l e0+e1 rest-partitions)
>>>>         (conde
>>>>             ;; Base case
>>>>             ((== l '())
>>>>                 (== partitions '())))
>>>>
>>>>             ;; Recursive case
>>>>             ((== partitions `((,e0 ,e1 ,e2) . ,rest-partitions))
>>>>                 (riffleo `(,e0 ,e1 ,e2) rest-l l)
>>>>                 (+o e0 e1 e0+e1)
>>>>                 (+o e0+e1 e2 sum)
>>>>                 (three-partitiono rest-l rest-partitions sum))))
>>>>
>>>>
>>>> Has anyone else encountered this riffle relation?
>>>>
>>>> Best,
>>>> Brett Schreiber
>>>>
>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "minikanren" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/minikanren/ac5e6700-f7c6-4e1c-8915-d9db0907c715n%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/minikanren/ac5e6700-f7c6-4e1c-8915-d9db0907c715n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>

-- 
You received this message because you are subscribed to the Google Groups 
"minikanren" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/minikanren/6b3e62d1-62f7-4d45-bfd1-340fa76ea2den%40googlegroups.com.

Reply via email to