Skip to content

Instantly share code, notes, and snippets.

@jlumpe
Last active November 10, 2022 00:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlumpe/dabd62e3f209633eea60da205af0dd45 to your computer and use it in GitHub Desktop.
Save jlumpe/dabd62e3f209633eea60da205af0dd45 to your computer and use it in GitHub Desktop.
My set of custom LaTeX macros
#!/bin/bash
# Create and install tex package for macros
set -ex
TEXMFHOME=`kpsewhich -var-value=TEXMFHOME`
dir="$TEXMFHOME/tex/latex/custom"
mkdir -p "$dir"
./mathmacros.py sty > "$dir/mymath.sty"
#!/usr/bin/env python
"""Defines the macros, and outputs in one of several formats."""
import sys
import os
# Format is "commandname": ("value", numargs)
MACROS = {
# Vector and matrix variables
'Vect': (r'\boldsymbol{#1}', 1),
'Mat': (r'\boldsymbol{#1}', 1),
# Specific symbols as vectors/matrices
'Vectmu': (r'\Vect{\mu}', 0),
'Vectx': (r'\Vect{x}', 0),
'Vecty': (r'\Vect{y}', 0),
'Vectu': (r'\Vect{u}', 0),
'Vectv': (r'\Vect{v}', 0),
'MatSigma': (r'\Mat{\Sigma}', 0),
# Number sets
'Reals': (r'\mathbb{R}', 0),
'Complexes': (r'\mathbb{C}', 0),
'Rationals': (r'\mathbb{Q}', 0),
'Integers': (r'\mathbb{Z}', 0),
'Naturals': (r'\mathbb{N}', 0),
'Vectors': (r'\Reals^{#1}', 1),
'Matrices': (r'\Reals^{#1 \times #2}', 2),
# Partial derivatives
'Partial': (r'\frac{\partial #1}{\partial #2}', 2),
'Partiall': (r'\frac{\partial #1^2}{\partial #2 \partial #3}', 3),
'Partialll': (r'\frac{\partial #1^3}{\partial #2 \partial #3 \partial #4}', 4),
# KL divergence
'DKL': (r'D_\text{KL}(#1 \parallel #2)', 2),
# Quadratic form, like x^T A x
'Quadform': (r'#1^T #2 #1', 2),
'Quadformt': (r'#1 #2 #1^T', 2),
}
REQUIRED_PACKAGES = ['amsmath', 'amsfonts', 'mathtools']
# Raw tex to append
TEX = r"""
% Absolute value and magnitude
% https://tex.stackexchange.com/questions/43008/absolute-value-symbols
\DeclarePairedDelimiter\abs{\lvert}{\rvert}%
\DeclarePairedDelimiter\norm{\lVert}{\rVert}%
% Swap the definition of \abs* and \norm*, so that \abs
% and \norm resizes the size of the brackets, and the
% starred version does not.
\makeatletter
\let\oldabs\abs
\def\abs{\@ifstar{\oldabs}{\oldabs*}}
%
\let\oldnorm\norm
\def\norm{\@ifstar{\oldnorm}{\oldnorm*}}
\makeatother
"""
# Test usage for macros
MACRO_EXAMPLES = {
macro: ['\\' + macro] if nargs == 0 else []
for macro, (_, nargs) in MACROS.items()
}
MACRO_EXAMPLES['Vect'] = [r'\Vect{x}']
MACRO_EXAMPLES['Mat'] = [r'\Mat{X}']
MACRO_EXAMPLES['Vectors'] = [r'\Vectors{n}']
MACRO_EXAMPLES['Matrices'] = [r'\Matrices{n}{m}']
MACRO_EXAMPLES['Partial'] = [
r'\Partial{f}{x}',
r'\Partial{}{x} f(x)',
]
MACRO_EXAMPLES['Partiall'] = [
r'\Partiall{f}{x}{y}',
r'\Partiall{}{x}{y} f(x, y)'
]
MACRO_EXAMPLES['Partialll'] = [
r'\Partialll{f}{x}{y}{z}',
r'\Partialll{}{x}{y}{z} f(x, y, z)',
]
MACRO_EXAMPLES['DKL'] = [r'\DKL{x}{y}']
MACRO_EXAMPLES['Quadform'] = [r'\Quadform{\Vect{x}}{\Mat{A}}']
MACRO_EXAMPLES['Quadformt'] = [r'\Quadformt{\Vect{x}}{\Mat{A}}']
MACRO_EXAMPLES['abs'] = [
r'\abs{x}',
r'\abs{\frac{x}{y}}',
r'\abs*{\frac{x}{y}}',
]
MACRO_EXAMPLES['norm'] = [
r'\norm{\Vect{u}}',
r'\norm{\frac{1}{2}\Vect{u} + \frac{1}{2}\Vect{v}}',
r'\norm*{\frac{1}{2}\Vect{u} + \frac{1}{2}\Vect{v}}',
]
def newcommand(name, command, nargs=0):
if nargs > 0:
return r'\newcommand{\%s}[%d]{%s}' % (name, nargs, command)
else:
return r'\newcommand{\%s}{%s}' % (name, command)
def print_tex():
for name, (command, nargs) in MACROS.items():
print(newcommand(name, command, nargs))
print('\n\n')
print(TEX)
def print_mathjax():
import json
print('{')
for i, (name, (command, nargs)) in enumerate(MACROS.items()):
namejson = json.dumps(name)
cmdjson = json.dumps(command)
end = ',\n' if i < len(MACROS) - 1 else '\n'
if nargs > 0:
print('\t%s: [%s, %d]' % (namejson, cmdjson, nargs), end=end)
else:
print('\t%s: %s' % (namejson, cmdjson), end=end)
print('}')
def print_sty():
for package in REQUIRED_PACKAGES:
print(r'\RequirePackage{%s}' % package)
print()
print_tex()
def _print_macros_table(vspace='1ex', vstretch=None, borders=False, align='l'):
max_examples = max(map(len, MACRO_EXAMPLES.values()))
nextrow = r'\\[%s]' % vspace if vspace else r'\\'
if borders:
nextrow += ' \\hline'
if vstretch is not None:
print('\\renewcommand{\\vstretch}{%s}\n' % vstretch)
v = '|' if borders else ''
cols_arg = v + 'l' + v + (align * max_examples) + v
print(r'\begin{longtable}{ %s }' % cols_arg)
if borders:
print('\\hline')
for macro, examples in MACRO_EXAMPLES.items():
print('\\verb+\\', macro, '+ ', sep='', end='')
for i, example in enumerate(examples):
print('& $\\displaystyle', example, '$ ', end='')
print(nextrow)
print(r'\end{longtable}')
def print_example(pkgname='mymath'):
packages = [pkgname, 'longtable', *REQUIRED_PACKAGES]
# Preamble
print(r'\documentclass{article}')
print()
for package in packages:
print(r'\RequirePackage{%s}' % package)
print('\n\\begin{document}')
# Macros table
print('\n\\section{Macros}')
print()
_print_macros_table()
# Other stuff
#print('\n\\section{Other}')
print('\n\\end{document}')
PRINTERS = {
'tex': (print_tex, 'Plain TEX file with macro definitions.'),
'mathjax': (print_mathjax, 'MathJax JSON.'),
'sty': (print_sty, '.sty file with required package imports and macro definitions.'),
'example': (print_example, 'TEX file with example usage of all defined commands.'),
}
def print_usage():
print('Usage: %s FORMAT' % os.path.basename(sys.argv[0]))
print()
print('Available formats:')
for fmt, (f, desc) in PRINTERS.items():
print('\t{}: {}'.format(fmt, desc))
if __name__ == '__main__':
if len(sys.argv) != 2:
print_usage()
sys.exit(1)
fmt = sys.argv[1].lower()
if fmt not in PRINTERS:
print_usage()
sys.exit(1)
f, desc = PRINTERS[fmt]
f()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment