1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
|
-- requires penlight
local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl
local bind = bind or pl.func.bind
function help_wrt(s1, s2) -- helpful printing, makes it easy to debug, s1 is object, s2 is note
local wrt = wrt or texio.write_nl
local wrt = wrt or print
s2 = s2 or ''
wrt('\nvvvvv '..s2)
if type(s1) == 'table' then
wrt(pl.pretty.write(s1))
else
wrt(tostring(s1))
end
wrt('^^^^^\n')
end
function prt_array2d(t)
for _, r in ipairs(t) do
local s = ''
for _, v in ipairs(r) do
s = s.. tostring(v)..', '
end
print(s)
end
end
-- -- -- -- --
-- -- -- -- functions below are helpers for arrays and 2d
local function compare_elements(a, b, op, ele)
op = op or pl.oper.gt
ele = ele or 1
return op(a[ele], b[ele])
end
local function comp_2ele_func(op, ele) -- make a 2 element comparison function,
--sort with function on element nnum
return bind(compare_elements, _1, _2, op, ele)
end
-- -- -- --
local function check_index(ij, rc) -- converts array index to positive value if negative
if type(ij) ~= 'number' then
return 1
else
if ij < 0 then
ij = rc + ij + 1
elseif ij > rc then
ij = rc
end
return ij
end
end
local function check_slice(M, i1, j1, i2, j2) -- ensure a slice is valid; i.e. all positive numbers
r, c = pl.array2d.size(M)
i1 = check_index(i1, r)
i2 = check_index(i2, r)
j1 = check_index(j1, c)
j2 = check_index(j2, c)
return i1, j1, i2, j2
end
local function check_func(func) -- check if a function is a PE, if so, make it a function
if type(func) ~= 'function' then
__func = I(func)
end
return __func
end
-- -- -- -- -- -- --
-- -- -- -- functions below extend the array2d module
local function map_slice1(func, L, i1, i2) -- map a function to a slice of an array, can use PlcExpr
i2 = i2 or i1
local len = #L
i1 = check_index(i1, len)
i2 = check_index(i2, len)
func = check_func(func)
for i in pl.seq.range(i1,i2) do
L[i] = func(L[i])
end
return L
end
local function map_slice2(func, M, i1, j1, i2, j2) -- map a function to a slice of a Matrix
i1, j1, i2, j2 = check_slice(M, i1, j1, i2, j2)
--for i,j in array2d.iter(M, true, i1, j1, i2, j2) do --todo this did not work, penlight may have fixed this
func = check_func(func)
for i in pl.seq.range(i1,i2) do
for j in pl.seq.range(j1,j2) do
M[i][j] = func(M[i][j])
end
end
return M
end
local function map_columns(func, M, j1, j2) -- map function to columns of matrix
j2 = j2 or j1
return map_slice2(func, M, 1, j1, -1, j2)
end
local function map_rows(func, M, i1, i2) -- map function to rows of matrix
i2 = i2 or i1
return map_slice2(func, M, i1, 1, i2, -1)
end
-- -- -- -- -- -- -- --
function sortOP(M, op, ele) -- sort a 2d array based on operator criteria, ele is column, ie sort on which element
M_new = {}
for row in pl.seq.sort(M, comp_2ele_func(op, ele)) do
M_new[#M_new+1] = row
end
return M_new
end
local function like(M1, v)
v = v or 0
r, c = pl.array2d.size(M1)
return pl.array2d.new(r,c,v)
end
function from_table(t) -- turns a labelled table to a 2d, label-free array
t_new = {}
for k, v in pairs(t) do
if type(v) == 'table' then
t_new_row = {k}
for _, v_ in ipairs(v) do
t_new_row[#t_new_row+1] = v_
end
t_new[#t_new+1] = t_new_row
else
t_new[#t_new+1] = {k, v}
end
end
return t_new
end
function toTeX(M, EL) --puts & between columns, can choose to end line with \\ if EL is true (end-line)
EL = EL or false
if EL then EL = '\\\\' else EL = '' end
return pl.array2d.reduce2(_1..EL.._2, _1..'&'.._2, M)..EL
end
-- -- -- -- -- -- --
-- add to array2d module
pl.array2d['map_columns'] = map_columns
pl.array2d['map_rows'] = map_rows
pl.array2d['map_slice2'] = map_slice2
pl.array2d['map_slice1'] = map_slice1
pl.array2d['from_table'] = from_table
pl.array2d['toTeX'] = toTeX
pl.array2d['sortOP'] = sortOP
pl.array2d['like'] = like
-- -- -- -- -- -- -- -- -- -- -- -- functions below extend the operator module
local function strgt(a,b) return tostring(a) > tostring(b) end
local function strlt(a,b) return tostring(a) < tostring(b) end
pl.operator['strgt'] = strgt
pl.operator['strlt'] = strlt
local function gextract(s, pat) --extract a pattern from string, returns both
local s_extr = ''
local s_rem = s
for e in s:gmatch(pat) do
s_extr = s_extr..e
s_rem = s_rem:gsub(e,'')
end
return s_extr, s_rem
end
local function gfirst(s, t) -- get the first pattern found from a table of pattern
for _, pat in pairs(t) do
if string.find(s, pat) then
return pat
end
end
end
local function appif(S, W, B, O) --append W ord to S tring if B oolean true, otherwise O ther
--append Word to String
if B then --if b is true
S = S .. W
else --consider Other word
O = O or ''
S = S .. O
end
return S
end
local mt = getmetatable("") -- register functions with str
mt.__index["gextract"] = gextract
mt.__index["gfirst"] = gfirst
mt.__index["app_if"] = appif
function mod(a, b) -- math modulo, return remainder only
return a - (math.floor(a/b)*b)
end
function mod2(a) -- math modulo 2
return mod(a,2)
end
function hasval(x) -- if something has value
-- todo check for Lists, other penlight objects
if (x == nil) or (x == false) or (x == 0) or (x == '') then
return false
elseif type(x) == 'table' then
if #x == 0 then
return false
else
return true
end
end
return true
end
-- testing here
____zzz__ = [[
function hasStrKey(T)
--checks if a Table contains a string-type key
local hasaStrKey = false
for k, v in pairs(T) do --look through table pairs
if type(k) == "string" then --if any string found, return true
hasaStrKey = true
break
end
end
return hasaStrKey
end
function any()
--todo go through table or list of args and return true of anything is something
end
function all()
--todo go through table or list of args and return true of anything is something
end
--elseif x == {} then
-- return false
n = nil
b = false
z = 0
e = ''
t = {}
--s = 'a'
--n = 1
if is(nil) then
print('TRUE')
else
print('FALSE')
end
--print({}=={})
--print(0.0==0)
]]
-- Some simple and helpful LaTeX functions
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--Generic LuaLaTeX utilities for print commands or environments
-- http://lua-users.org/wiki/SplitJoin -- todo read me!!
__SKIP_TEX__ = __SKIP_TEX__ or false --if declared true before here, it will use regular print functions
-- (for troubleshooting with texlua)
-- xparse defaults
_xTrue = '\\BooleanTrue '
_xFalse = '\\BooleanFalse '
_xNoValue = '-NoValue-'
if not __SKIP_TEX__ then
prt = tex.sprint --can print lists, but will NOT put new line between them
prtn = tex.print --can print lists and will put new line. C-function not in Lua. think P rint R return
wrt = texio.write
wrtn = texio.write_nl
else
prt = io.write
prtn = print --print with new line
wrt = io.write
wrtn = io.write_nl
end
function prtl(str) -- prints a literal string to latex, adds new line between them
for line in str:gmatch"[^\n]*" do -- gets all characters up to a new line
prtn(line)
end
end
_NumBkts = 0
function reset_bkt_cnt(n)
n = n or 0
_NumBkts = n
end
function add_bkt_cnt(n)
n = n or 1
_NumBkts = _NumBkts + n
end
function close_bkt_cnt()
local s = ('}'):rep(_NumBkts)
reset_bkt_cnt()
return s
end
--definition helpers -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- todo add this
local function defcmd_nest(cs) -- for option if you'd like your commands under a parent ex. \csparent{var}
tex.print('\\gdef\\'..cs..'#1{\\csname '..var..'--#1--\\endcsname}')
end
local function defcmd(cs, val, nargs)
if (nargs == nil) or (args == 0) then
token.set_macro(cs, tostring(val), 'global')
else
local args = '#1'
tex.print('\\gdef\\'..cs..args..'{'..val..'}')
-- todo https://tex.stackexchange.com/questions/57551/create-a-capitalized-macro-token-using-csname
-- \expandafter\gdef\csname Two\endcsname#1#2{1:#1, two:#2} --todo do it like this
end
end
local function prvcmd(cs, val) -- provide command via lua
if token.is_defined(cs) then
tex.print('\\PackageWarning{YAMLvars}{Variable '..cs..' already defined, could not declare}{}')
else
defcmd(cs, val)
end
end
local function newcmd(cs, val) -- provide command via lua
if token.is_defined(cs) then
tex.print('\\PackageError{luadefs}{Command '..cs..' already defined}{}')
else
defcmd(cs, val)
end
end
local function renewcmd(cs, val) -- provide command via lua
if token.is_defined(cs) then
defcmd(cs, val)
else
tex.print('\\PackageError{luadefs}{Command '..cs..' already defined}{}')
end
end
local function deccmd(cs, def)
if def == nil then
prvcmd(cs, '\\PackageError{luadefs}{Command "'..cs..'" was declared and used but, not set}{}')
else
prvcmd(cs, def)
end
end
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|