Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symmetry operator of -< #128

Open
chansey97 opened this issue Dec 8, 2023 · 3 comments
Open

Symmetry operator of -< #128

chansey97 opened this issue Dec 8, 2023 · 3 comments

Comments

@chansey97
Copy link

The operator -< currently is not symmetrical, i.e. lacks its mirror operator >-.

Two examples are provided below to demonstrate why it is useful.

The 1st one is the matrix addition.

Here is a possible solution:

;; 1 8 5
;; 3 4 3
;; 8 2 1
(define-flow D
  (~> (-< (~> (== (* 1) (* 8) (* 5)) +)
          (~> (== (* 3) (* 4) (* 3)) +)
          (~> (== (* 8) (* 2) (* 1)) +))))
          
;; 9 4 2
;; 5 4 7
;; 8 4 7
(define-flow E
  (~> (-< (~> (== (* 9) (* 4) (* 2)) +)
          (~> (== (* 5) (* 4) (* 7)) +)
          (~> (== (* 8) (* 4) (* 7)) +))))

(define-flow D+E
  (~>> (-< (~> E ▽) (~> D ▽)) (map +)))

The D+E seems ugly, because we have to collect them into a list, but I would like to write it like the following, if possible:

(define-flow D+E
  (~> (-< D E) (>- +)))

This example is inspired from Graphical Linear Algebra. In GLA, Pawel introduced a syntactic sugar called "m-wire". so the the string diagram of matrix addition can be simplified to:

Pasted_image_20231204062326

Image from https://www.cs.ox.ac.uk/qpl2015/slides/sobocinski-tutorial.pdf p.25

The 2nd comes from meru.rkt

(define-flow meru-step
  (~>> (-< (~> (-< 0 _) ▽) 
           (~> (-< _ 0) ▽))
       (map +) △))

Using the expected operator >-, the solution would be more concise:

(define-flow meru-step
  (~>> (-< (~> (-< 0 _))
           (~> (-< _ 0)))
       (>- +) △))

P.S. This issue has been discussed on Racket Discord and @countvajhula proposed a solution. Currently we could write the following macro to workaround it.

(require (for-syntax racket/base syntax/parse))

(define-qi-syntax-rule (-<> f ... ((~datum >-) comb))
  (~>> (-< (~> f ▽) ...) (map comb)))

(define-flow D+E
  (~> (-<> D E (>- +))))

More details see https://discord.com/channels/571040468092321801/979642553471221790/1182246331922780251

@NoahStoryM
Copy link
Collaborator

NoahStoryM commented Dec 8, 2023

Hello @chansey97

I agree that the -< operator should have a symmetric counterpart. In Qi, the values we work with can be viewed categorically as product objects, which naturally have a dual concept: sum objects. Therefore, not only -<, but other operators such as ><, ==*, fanout, n>, , etc., that handle values (product objects), should also have symmetric operators for handling covalues (sum objects), like <>, ==+, fanin, n<, , etc.. Here is our previous discussion: #62 (comment).

I’ve previously developed qi-cat, which implements these dual operators. Unfortunately, due to personal reasons, I haven’t been able to produce comprehensive documentation for it (I plan to address this when time permits).

To briefly introduce covalues, it's essentially values tagged with a natural number. For instance, (values 1 "a") represents a value in Number × String, whereas (covalues '(1 2) 0) and (covalues '(a b) 1) represent values in (Number × Number) + (Symbol × Symbol).

The -< operator corresponds to the categorical concept of pairing. For example, given a : G -> X and b : G -> Y, then (-< a b) : G -> X × Y.

The dual of -< is >-, known as copairing, which operates as follows: given a : X -> T and b : Y -> T, then (>- a b) : X + Y -> T.

@countvajhula
Copy link
Collaborator

Btw @NoahStoryM , unrelated to the present issue but, we are gearing up to release Qi 4 which includes the optimizing compiler. One of the big changes with backwards compatibility implications is the change from matching datum literals (~datum) to matching literals (~literal). See Literally Causing Problems for more details on how this can affect applications. If you have time, you may want to test qi-cat with the lets-write-a-qi-compiler branch to see if it is affected (but you may want to wait until later today as we are hoping to merge a few PRs including First Optimizations). It would also be helpful in general to see if we've broken anything else!

@NoahStoryM
Copy link
Collaborator

NoahStoryM commented Dec 10, 2023

Hi @countvajhula ,

I’ve tried lets-write-a-qi-compiler and all the qi-cat tests passed. I didn’t notice any issues.

Also, I read @chansey97’s code and I found an interesting way. It seems that we can perform a matrix-like transpose operation on the values processed by qi. For example, (~> (1 1 1) (-< D E)) results in (values 14 10 11 15 16 19), which we can view as a 3×2 matrix. If we transpose it, we get (values 14 15 10 16 11 19), and then we can use ><, which can distribute input values (#64) , to get (values 29 26 30).

Here is the code:

#lang racket

(require qi/cat (for-syntax syntax/parse))

;; 1 8 5
;; 3 4 3
;; 8 2 1
(define-flow D
  (~> (-< (~> (== (* 1) (* 8) (* 5)) +)
          (~> (== (* 3) (* 4) (* 3)) +)
          (~> (== (* 8) (* 2) (* 1)) +))))

;; 9 4 2
;; 5 4 7
;; 8 4 7
(define-flow E
  (~> (-< (~> (== (* 9) (* 4) (* 2)) +)
          (~> (== (* 5) (* 4) (* 7)) +)
          (~> (== (* 8) (* 4) (* 7)) +))))

(define add (procedure-reduce-arity + 2))
(define-syntax for/values
  (syntax-parser
    [(_ (clause ...) body ...+)
     #'(apply values (for/list (clause ...) body ...))]))
(define (transpose* m n)
  (λ arg*
    (define v* (list->vector arg*))
    (for/values ([id (in-range (* m n))])
      (define-values (j i) (quotient/remainder id n))
      (vector-ref v* (+ (* i m) j)))))

(define-flow D+E (~> (-< D E) (transpose* 3 2) (>< add)))

And it's not hard to implement the dual operator transpose+, which deals with covalues.

By the way, for/values seems to be very useful for qi. Do you think it’s worth considering implementing it in qi?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants