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

Specialized Support for Arrays #15

Open
bohrium opened this issue Mar 30, 2021 · 5 comments
Open

Specialized Support for Arrays #15

bohrium opened this issue Mar 30, 2021 · 5 comments
Labels
enhancement New feature or request

Comments

@bohrium
Copy link

bohrium commented Mar 30, 2021

One of the most annoying-times-frequency things among my latex experiences is making 2d grids by describing them using 1d text. Such grids include matrices, commutative diagrams, tables, multi-line derivations whose terms are aligned, and more. It'd be neat to provide a special "array mode" for parsing and editing text of the form

A & B & C & D & E \\  
A & B & C & D & E \\  
A & B & C & D & E \\  
A & B & C & D & E

This is the syntax for the latex body in each of all four examples above. The cells(' latex expressions) will typically all differ in length, creating a headache (do we spend time inserting white-space to align the columns, maintaining this alignment when we modify the cells? or do we ignore alignment issues in the source code and just count in our head when editing each row?)

It would be nice if when one's cursor enters a latex block of the above form, the cells in the latex block automatically align (wrt the ampersands and line-break symbols). If I correctly understand the spirit of prosemirror-math, one wants to avoid having popup dialog boxes or editors separate from the text. So perhaps the alignment could be as simple as inserting appropriate whitespace when the block is "active"!

@bohrium bohrium changed the title specialized support for arrays Specialized Support for Arrays Mar 30, 2021
@benrbray benrbray added the enhancement New feature or request label Mar 30, 2021
@benrbray
Copy link
Owner

I agree, this is a common pain point for me as well, and I've been mulling over solutions in my head for a while. Getting the workflow right is tricky, but I'm happy to discuss possibilities. Although the examples you listed share a common syntax, I think they appear in quite different contexts and will need to be handled differently. We will also be limited by the commands supported by KaTeX / MathJax.

  • Matrices tend to appear as subexpressions of a larger math block, and more than one matrix may appear in a single expression. How should the editor behave for something like this?
A x = \begin{bmatrix}
   a_{11} & a_{12} \\
   a_{21} & a_{22}
\end{bmatrix}
\begin{bmatrix}
	x_1 \\ x_2
\end{bmatrix}
  • Tables tend to appear by themselves, so it might be as simple as enabling prosemirror-tables extension with some special code for serialization to LaTeX.

  • I suspect that everyone has different preferences for how to format multi-line derivations, so it might be difficult to standardize, especially when nested brackets are involved. Personally I tend to use multiple indented lines for nested brackets, and I'll often wrap manually if lines get too long. For example,

\begin{aligned}
\EE_{q(x)}\left[  (x-\mu_A)^T \Sigma_A^{-1} (x-\mu_A) \right]
&= \EE\left[
        \trace\left( (x-\mu_A)^T \Sigma_A^{-1} (x-\mu_A) \right)
    \right] 
    & \text{(trace of scalar)} \\
&= \EE\left[
        \trace\left( \Sigma_A^{-1} (x-\mu_A) (x-\mu_A)^T \right)
    \right]
    & \text{(cyclicity)}\\
&= \trace\left( \EE\left[
        \Sigma_A^{-1} (x-\mu_A) (x-\mu_A)^T
    \right] \right)
    &\text{(linearity)}\\
&= \trace\left( \Sigma_A^{-1} \EE\left[
        (x-\mu_A) (x-\mu_A)^T
    \right] \right) 
    &\text{(linearity)}\\
&= \trace\left( \Sigma_A^{-1} \left[
        \Sigma_B + (\mu_B - \mu_A)(\mu_B - \mu_A)^T
    \right] \right)
    &\text{(eqn\;\ref{eqn:gauss-quadratic-form})} \\
&= \trace\left( \Sigma_A^{-1} \Sigma_B \right)
    + (\mu_B - \mu_A)^T \Sigma_A^{-1} (\mu_B - \mu_A)
    &\text{(cyclicity; linearity)}
\end{aligned}
  • Commutative diagrams are tricky, because neither KaTeX nor MathJax has great support for them out of the box. It would be helpful to collect some examples of source code for commutative diagrams that we expect prosemirror-math to be able to handle. The best tool I know of for editing commutative diagrams on the web is quiver, so worst case we might be able to introduce a new type of math node that makes it easy to embed diagrams made with quiver.

@bohrium
Copy link
Author

bohrium commented Mar 30, 2021

Cool! Your points about differences in context implying differences in handling make a lot of sense to me. I'll mull over.

Quick comments:

quiver seems to generate tikz blocks, but katex does not support tikz's environments (I think). It seems they support the amscd "CD" environment (CD stands for commutative diagram), which is a very bare bones package that can express perhaps 80% of the simple diagrams a math student might draw and that can render them correctly perhaps 80% of the time.

matrices as sub-expressions : the general design problem is as you mention tricky, so I'll discuss the much easier case where I'm allowed to overfit to my own tastes 😄. I would feel happy if the example given is auto formatted to look like

A x =
\begin{bmatrix}                                                                 
    loremipsum & 1      \\                                                      
    0          & moocow                                                         
\end{bmatrix}                                                                   
\begin{bmatrix}                                                                 
    whole       \\                                                              
    two-percent                                                                 
\end{bmatrix} 

However, I can imagine folks and cases that favor a more compact style such as:

A x = \begin{bmatrix} loremipsum & 1      \\                                    
                      0          & moocow \end{bmatrix} \begin{bmatrix} whole \\ two-percent \end{bmatrix}

Here, only the "hard-to-parse" first matrix is formatted in an aligned way. I don't see how to approximate this latter style programatically --- or whether to so attempt would be useful.

multiline derivations: i bet the following two rules are common to many personal styles:

  • the source for each (rendered) row starts on a new line.
  • the (source) column c(k,j) containing the kth ampersand in the jth (rendered) row depends only on k, not j.

For example, both hold in the example you showed (for for the two values of k, we have c=0 and then c=4). So perhaps something good here be to insert spaces according to this "weak rule" rather than insisting on a canonical form. Thus, the formatter would not override extra newlines and extra indentation provided by the user.

Here's a simple example of what it would love to see when modifying a multiline derivation. Say we start with

\begin{align}
    a                                                                           
    &= \left(                                                                   
           itwasthebestoftimes                                                  
       \right)                                                                  
       moo   & \left\langle                                                     
                   itwastheworstoftimes                                         
               \right\rangle& woah                                              
        & true \\                                                               
    &= \left(                                                                   
           itwastheageofwisdom                                                  
       \right)                                                                  
       cow   & \left(                                                           
                   itwastheageoffoolishness                                     
               \right)_0    & woah \\                                           
        & true \\                                                               
    &                                &                                          
                            & woah                                              
        & true                                                                  
\end{align}

Upon replacing "cow" by "iamafundamoomentallygoodcow", we see

\begin{align}                                                                   
    a                                                                           
    &= \left(                                                                   
           itwasthebestoftimes                                                  
       \right)                                                                  
       moo                           & \left\langle                             
                                           itwastheworstoftimes                 
                                       \right\rangle& woah                      
        & true \\                                                               
    &= \left(                                                                   
           itwastheageofwisdom                                                  
       \right)                                                                  
       iamafundamoomentallygoodcow   & \left(                                   
                                           itwastheageoffoolishness             
                                       \right)_0    & woah \\                   
        & true \\                                                               
    &                                &                                          
                                                    & woah                      
        & true                                                                  
\end{align}

Then, upon replacing the "\rangle" by ")", we see

\begin{align}
    a                                                                           
    &= \left(                                                                   
           itwasthebestoftimes                                                  
       \right)                                                                  
       moo                           & \left\langle                             
                                           itwastheworstoftimes                 
                                       \right)  & woah                          
        & true \\                                                               
    &= \left(                                                                   
           itwastheageofwisdom                                                  
       \right)                                                                  
       iamafundamoomentallygoodcow   & \left(                                   
                                           itwastheageoffoolishness             
                                       \right)_0& woah \\                       
        & true \\                                                               
    &                                &                                          
                                                & woah                          
        & true                                                                  
\end{align}

@bohrium
Copy link
Author

bohrium commented Mar 30, 2021

As for diagrams, here are what some that come to mind. They go from most to least common and from least to most complex. From the implementation standpoint they are similar: each is a combination of basic parts. But from the usability standpoint each might say something different about what interfaces best aid mathematical writing.

lifting diagram

\begin{tikzcd}
                               & P \arrow[d, "g"] \arrow[ld, "l"', dotted] \\
X \arrow[r, "\pi"', two heads] & Y                                        
\end{tikzcd}

see this link

causal model

\begin{tikzcd}
                                                                 & \substack{\text{sensor}\\ \text{placement}} \arrow[rd] \arrow[rrd] &                                                     &                                              \\
\substack{\text{attentive}\\ \text{nurse}} \arrow[ru] \arrow[rd] &                                                                    & \substack{\text{sensor}\\ \text{reading}} \arrow[r] & \substack{\text{guessed}\\ \text{heartrate}} \\
                                                                 & \substack{\text{true}\\ \text{heartrate}} \arrow[ru]               &                                                     &                                             
\end{tikzcd}

see this link

naturality

\begin{tikzcd}
                                     & a \arrow[ldd, no head, dotted] \arrow[rd, no head, dotted] \arrow[rr] &               & b \arrow[rd, no head, dotted] \arrow[dd, no head, dotted] &    \\
                                     &                                                                       & Ga \arrow[rr] &                                                           & Gb \\
Fa \arrow[rrr] \arrow[rru, "\eta_a"] &                                                                       &               & Fb \arrow[ru, "\eta_b"]                                   &   
\end{tikzcd}

see this link

finite-state automaton

\begin{tikzcd}
\to q_0 \arrow[r, "a"] \arrow["b", loop, distance=2em, in=235, out=305] & q_1 \arrow[r, "a"] \arrow[l, "b"', bend left=49] & q_2 \arrow[r, "a"] \arrow[ll, "b"', bend left=49] & \boxed{q_3} \arrow["{a,b}", loop, distance=2em, in=235, out=305]
\end{tikzcd}

see this link

@bohrium
Copy link
Author

bohrium commented Apr 5, 2021

Let me know if any of these ideas sounds like a good starting point that I might try to implement!

@benrbray
Copy link
Owner

benrbray commented Apr 6, 2021

I think we agree on the rough ux, so I'm happy to continue the feedback loop with you if you start on a prototype! Some things to ponder:

  • I plan to add support for MathJax, for those who want it, along with extensions like XyJax for commutative diagrams. It's unfortunate that the KaTeX \begin{CD} environment doesn't support diagonal arrows. So, you can design with something like XyJax in mind.

  • How do you plan to implement this functionality? As an actual <table> element that gets converted to LaTeX? Or as a string processor that adjusts the contents of the text input field automatically as you type? We'll need to think carefully about the right way for a user to "activate" the array-style editing mode, since having it on by default might confuse users. One option is to create a new NodeView activated by a different character sequence (like $$matrix or \begin{matrix} etc) that offers the array-style mode. You can use the existing math NodeView as a reference.

  • In order to contribute code to this repo, it will be important to understand the transaction-based model of ProseMirror. The ProseMirror guide is a good starting point. Right now, the math editor appears in a NodeView that contains another mini-instance of ProseMirror. So, if you make any changes to how the inner editor behaves, they will need to respect the transactional model. (meaning you can't just set e.g. textField.textContent = adjustSpacing(textField.textContent) every time you want to make a change)

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

No branches or pull requests

2 participants