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

Restate a theorem, or restate all theorems, elsewhere in document? #8

Open
davidleejy opened this issue Sep 17, 2023 · 8 comments
Open

Comments

@davidleejy
Copy link

davidleejy commented Sep 17, 2023

I was mulling about how convenient it would be for someone writing a summary to have the ability to restate (i.e. re-print/ repeat) a theorem, or restate all theorems, elsewhere in the document, for example to restate theorems under a "List of Results" section.

Might someone know how to ...

  1. ... restate a theorem elsewhere in the document?

  2. ... restate all theorems elsewhere in the document? (maybe a script to traverse all theorems and print each one?)

  3. ... restate a selection of theorems elsewhere in the document? (This might be useful for generating a "List of Results" section at the end of each chapter)

@lumi-a
Copy link

lumi-a commented Jan 28, 2024

Here is a half-baked solution to your second question, using states:

#import "@preview/ctheorems:1.1.0": *

#let state-theorems = state("state-theorems", [])

#let theorem = thmbox(
  "thm-counter",
  "Theorem",
  namefmt: name => {
    state-theorems.update(x => [#x (#name)])
    (name)
  },
  bodyfmt: body => {
    state-theorems.update(x => [#x #body
  
  ])
    body
  },
)

= Theorems

#theorem[Here we state the first theorem.]
Other content
#theorem("Euler")[This is the second statement.]
Yet more content
#theorem[This is the third.]

= Summary

#state-theorems.display()

Rendering of above code

@StarlightScribe
Copy link

This feature is also very important for my use case. Specifically, I use the apxproof LaTeX package, which can automatically send proofs to the appendix and restate the theorem.

https://ctan.math.illinois.edu/macros/latex/contrib/apxproof/apxproof.pdf

@sahasatvik
Copy link
Owner

There is probably some hacky way of doing this using states. On the other hand, thmenvs are really just figures (with kind: thmenv), so there might be a way of exploiting that.

@StarlightScribe Thank you for the reference to apxproof; I confess that I've never used this before, but it seems worth replicating.

@sahasatvik
Copy link
Owner

Update: Here's a very verbose way of achieving this; it uses states like @lumi-a suggested. The fmt function for the theorem does the job of updating the theorems state which stores the theorem data (you can also choose which theorems are to be restated). The tricky part is getting the numbering right in the restated part.

#import "@preview/ctheorems:1.1.2": *
#show: thmrules

#set page(width: 6in, height: auto, margin: 1cm)
#let theorems = state("theorems", ())

#let thmfmt(name, number, body, restate: false) = {
  // Formatting
  if name != none {
    block[*Theorem #number* (#name)*.*#h(0.2em) #body]
  } else {
    block[*Theorem #number.*#h(0.2em) #body]
  }

  // Save information in state
  if restate {
    locate(loc => {
      theorems.update(x => {
        let thm = (
          name: name,
          number: number,
          body: body,
          location: loc
        )
        if x == none {
          return (thm, )
        } else {
          return x + (thm, )
        }
      })
    })
  }
}

#let theorem = thmenv(
  "theorem",
  none,
  none,
  thmfmt
).with(
  supplement: "Theorem"
)
#let proof = thmproof("proof", "Proof", inset: 0em)

//////

#theorem(restate: true)[
  This theorem will be restated.
]

#theorem[
  This theorem will _not_ be restated.
]

#theorem("Euler", restate: true)[
  This theorem will also be restated!
]
#proof[
  #lorem(30)
]


= Restated Theorems
#v(1em)

// #theorems.display()

#theorems.display(x => {
  for thm in x {
    // Extract number at correct location!
    let number = thmcounters.at(thm.location).at("latest")
    number = numbering("1.1", ..number)

    // Show theorem
    thmfmt(thm.name, number, thm.body)
  }
})

Output:
apx

@sahasatvik
Copy link
Owner

I am planning on implementing this feature in v2.0.0, by adding restate and defer options. Would you be interested in a setup like this (output) one? (@davidleejy, @StarlightScribe)

@davidleejy
Copy link
Author

davidleejy commented Feb 27, 2024

I am planning on implementing this feature in v2.0.0, by adding restate and defer options. Would you be interested in a setup like this (output) one? (@davidleejy, @StarlightScribe)

Hi @sahasatvik, thank you for having considered, and implemented the ability for users to restate and defer theorems, corollaries, proofs, etc. 🎆 🥳

Having read the pdf and typ files shared in your comment, I'd be inclined to say that things are looking pretty good for a "version 1" of this feature. 😄

I noticed the clever implementation of (what I think are) custom keys 🔑 that could be used to label individual blocks (by "block" I mean a typst-theorem block):

#corollary(restate: true, 
           restate-keys: ("Corollary", "Result") // Custom keys?
           )
[
  There are infinitely many composite numbers.
]

... and the ability to select which keys to filter in a restate call:

= Only Theorems and Corollaries

#thm-restate("Theorem", "Corollary")

= Only 'Results'

#thm-restate("Result")

The logic in #thm-restate("Theorem", "Corollary") appears to filter for blocks labelled either "Theorem", or "Corollary", or both.

Do you think that it'd be useful to offer users the ability to perform #thm-restate("X" and "Y"), where only blocks that are labelled "X" and "Y" are restated? (In contrast to "X" or "Y")

More generally, having the ability to involve logic in the filter seems helpful when working with lengthy documents containing a varied block types. For instance:

= Section A

#corollary(restate: true, 
           restate-keys: ("A", "Important")
           )
[ ... ]

= Section B
[...]

= Section C
[...]

= Section D
[...]

= List of Important Results 

#thm-restate( ("A" and "Important") or ("C" and "Important) )

Due to the possible difficulty of letting users specify logic in the key filter, it might be worth considering delaying implementing this to a future version of this feature. 😃

@sahasatvik
Copy link
Owner

sahasatvik commented Feb 27, 2024

More generally, having the ability to involve logic in the filter seems helpful when working with lengthy documents containing a varied block types.

That certainly makes a lot of sense, I should probably let thm-restate use any custom filtering function supplied to it (in addition to the default/simpler behaviour).


Update: The example (output) now features custom filtering functions (a filtering function tests a restate-keys array), along with an '("A" and "B") or ("C" and "D")' syntax. For instance, thm-restate(("A", "Important"), ("B", "Important"), "C") will match blocks marked as (A and Important) or (B and Important) or C.

Thanks for the feedback on this feature, I'll continue taking more suggestions for improvement!

@davidleejy
Copy link
Author

davidleejy commented Feb 27, 2024

Update: The example (output) now features custom filtering functions

That was fast 😆.

Thanks to your effort, in this implementation, from what I can tell, users are offered the ability to specify custom filters in DNF (disjunctive normal form), i.e., specify a filter in a form that's a disjunction of conjunctions:

#thm-restate(("Theorem", "Result"), "Definition")     
// Filter for blocks labelled:  (Theorem ⋀ Result) ⋁ Definition .

... and also specify a filter based on the existence of a substring across keys:

#thm-restate(keys => keys.any(x => x.contains("fi")))    
// Blocks labelled with the "Definition" key will be
// restated in this call because the string "fi" is a substring 
// in the key "Definition".

Once again, thank you @sahasatvik 🙏🏻 . I believe this feature will benefit authors of textbooks when creating a summary of results, say for an end-of-chapter recall/review, and students who desire to distill particular results from their Typst notes into helpsheets for use in exams, or into an abridged version of their notes.

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

4 participants