summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua
blob: cc39ddd607093e616fc651d073e79325acdd5a04 (plain)
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
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
-- Copyright 2012 by Till Tantau
--
-- This file may be distributed an/or modified
--
-- 1. under the LaTeX Project Public License and/or
-- 2. under the GNU Public License
--
-- See the file doc/generic/pgf/licenses/LICENSE for more information

-- @release $Header$



---
-- Basic library functions

local lib = {}

-- Declare namespace

require("pgf.gd").lib = lib


-- General lib functions:


---
-- Finds the first value in the |array| for which |test| is true.
--
-- @param array  An array to search in.
-- @param test   A function that is applied to each element of the
--               array together with the index of the element and the
--               whole table.
--
-- @return The value of the first value where the test is true.
-- @return The index of the first value where the test is true.
-- @return The function value of the first value where the test is
--         true (only returned if test is a function).
--
function lib.find(array, test)
  for i=1,#array do
    local t = array[i]
    local result = test(t,i,array)
    if result then
      return t,i,result
    end
  end
end


---
-- Finds the first value in the |array| for which a function
-- returns a minimal value
--
-- @param array  An array to search in.
-- @param f      A function that is applied to each element of the
--               array together with the index of the element and the
--               whole table. It should return an integer and, possibly, a value.
--
-- Among all elements for which a non-nil integer is returned, let |i|
-- by the index of the element where this integer is minimal.
--
-- @return |array[i]|
-- @return |i|
-- @return The return value(s) of the function at |array[i]|.
--
function lib.find_min(array, f)
  local best = math.huge
  local best_result
  local best_index
  for i=1,#array do
    local t = array[i]
    local result, p = f(t,i,array)
    if result and p < best then
      best = p
      best_result = result
      best_index = i
    end
  end
  if best_index then
    return array[best_index],best_index,best_result,best
  end
end




---
-- Copies a table while preserving its metatable.
--
-- @param source The table to copy.
-- @param target The table to which values are to be copied or |nil| if a new
--               table is to be allocated.
--
-- @return The |target| table or a newly allocated table containing all
--         keys and values of the |source| table.
--
function lib.copy(source, target)
  if not target then
    target = {}
  end
  for key, val in pairs(source) do
    target[key] = val
  end
  return setmetatable(target, getmetatable(source))
end


---
-- Copies an array while preserving its metatable.
--
-- @param source The array to copy.
-- @param target The array to which values are to be copied or |nil| if a new
-- table is to be allocated. The elements of the
-- |source| array will be added at the end.
--
-- @return The |target| table or a newly allocated table containing all
--         keys and values of the |source| table.
--
function lib.icopy(source, target)
  target = target or {}
  for _, val in ipairs(source) do
    target[#target+1] = val
  end
  return setmetatable(target, getmetatable(source))
end




---
-- Apply a function to all pairs of a table, resulting in a new table.
--
-- @param source The table.
-- @param fun A function taking two arguments (|val| and |key|, in
-- that order). Should return two values (a |new_val| and a
-- |new_key|). This pair will be inserted into the new table. If,
-- however, |new_key| is |nil|, the |new_value| will be inserted at
-- the position |key|. This means, in particular, that if the |fun|
-- takes only a single argument and returns only a single argument,
-- you have a ``classical'' value mapper. Also note that if
-- |new_value| is |nil|, the value is removed from the table.
--
-- @return The new table.
--
function lib.map(source, fun)
  local target = {}
  for key, val in pairs(source) do
    local new_val, new_key = fun(val, key)
    if new_key == nil then
      new_key = key
    end
    target[new_key] = new_val
  end
  return target
end



---
-- Apply a function to all elements of an array, resulting in a new
-- array.
--
-- @param source The array.
-- @param fun A function taking two arguments (|val| and |i|, the
-- current index). This function is applied to all elements of the
-- array. The result of this function is placed at the end of a new
-- array, expect when the function returns |nil|, in which case the
-- element is skipped. If this function is not provided (is |nil|),
-- the identity function is used.
-- @param new The target array (if |nil|, a new array is create).
-- %
--\begin{codeexample}[code only]
--  local a = lib.imap(array, function(v) if some_test(v) then return v end end)
--\end{codeexample}
--
-- The above code is a filter that will remove all elements from the
-- array that do not pass |some_test|.
-- %
--\begin{codeexample}[code only]
--  lib.imap(a, lib.id, b)
--\end{codeexample}
--
-- The above code has the same effect as |lib.icopy(a,b)|.
--
-- @return The new array
--
function lib.imap(source, fun, new)
  if not new then
    new = { }
  end
  for i, v in ipairs(source) do
    new[#new+1] = fun(v, i)
  end
  return new
end


---
-- Generate a random permutation of the numbers $1$ to $n$ in time
-- $O(n)$. Knuth's shuffle is used for this.
--
-- @param n The desired size of the table
-- @return A random permutation

function lib.random_permutation(n)
  local p = {}
  for i=1,n do
    p[i] = i
  end
  for i=1,n-1 do
    local j = lib.random(i,n)
    p[i], p[j] = p[i], p[j]
  end
  return p
end


---
-- The identity function, so you can write |lib.id| instead of
-- |function (x) return x end|.
--

function lib.id(...)
  return ...
end



---
-- Tries to find an option in different objects that have an
-- options field.
--
-- This function iterates over all objects given as parameters. In
-- each, it tries to find out whether the options field of the object
-- contains the option |name| and, if so,
-- returns the value. The important point is that checking whether the
-- option table of an object contains the name field is done using
-- |rawget| for all but the last parameter. This means that when you
-- write
-- %
--\begin{codeexample}[code only]
--lib.lookup_option("foo", vertex, graph)
--\end{codeexample}
-- %
-- and if |/graph drawing/foo| has an initial value set, if the
-- parameter is not explicitly set in a vertex, you will get the value
-- set for the graph or, if it is not set there either, the initial
-- value. In contrast, if you write
-- %
--\begin{codeexample}[code only]
-- vertex.options["foo"] or graph.options["foo"]
--\end{codeexample}
-- %
-- what happens is that the first access to |.options| will
-- \emph{always} return something when an initial parameter has been
-- set for the option |foo|.
--
-- @param name   The name of the options
-- @param ...    Any number of objects. Each must have an options
--               field.
--
-- @return The found option

function lib.lookup_option(name, ...)
  local list = {...}
  for i=1,#list-1 do
    local o = list[i].options
    if o then
      local v = rawget(o, name)
      if v then
        return v
      end
    end
  end
  return list[#list].options[name]
end



---
-- Turns a table |t| into a class in the sense of object oriented
-- programming. In detail, this means that |t| is augmented by
-- a |new| function, which takes an optional table of |initial| values
-- and which outputs a new table whose metatable is the
-- class. The |new| function will call the function |constructor| if
-- it exists. Furthermore, the class object's |__index| is set to itself
-- and its meta table is set to the |base_class| field of the
-- table. If |t| is |nil|, a new table is created.
--
-- Here is a typical usage of this function:
-- %
--\begin{codeexample}[code only]
--local Point = lib.class {}
--
--function Point:length()
--  return math.sqrt(self.x*self.x + self.y*self.y)
--end
--
--local p = Point.new { x = 5, y = 6 }
--
--print(p:length())
--\end{codeexample}
-- %
-- We can subclass this as follows:
-- %
--\begin{codeexample}[code only]
--local Point3D = lib.class { base_class = Point }
--
--function Point3D:length()
--  local l = Point.length(self) -- Call base class's function
--  return math.sqrt(l*l + self.z*self.zdy)
--end
--
--local p = Point3D.new { x = 5, y = 6, z = 6 }
--
--print(p:length())
--\end{codeexample}
--
-- @param t A table that gets augmented to a class. If |nil|, a new
-- table is created.
-- @return The augmented table.

function lib.class(t)
  t = t or {}

  -- First, setup indexing, if necessary
  if not t.__index then
    t.__index = t
  end

  -- Second, setup new method, if necessary
  t.new = t.new or
    function (initial)

      -- Create new object
      local obj = {}
      for k,v in pairs(initial or {}) do
        obj[k] = v
      end
      setmetatable(obj, t)

      if obj.constructor then
        obj:constructor()
      end

      return obj
    end

  -- Third, setup inheritance, if necessary
  if not getmetatable(t) then
    setmetatable(t, t.base_class)
  end

  return t
end



---
-- Returns a method that is loaded only on demand for a class.
--
-- The idea behind this function is that you may have a class (or just
-- a table) for which some methods are needed only seldomly. In this
-- case, you can put these methods in a separate file and then use
-- |ondemand| to indicate that the methods are found in a
-- another file.
-- %
--\begin{codeexample}[code only]
-- -- File Foo.lua
-- local Foo = {}
-- function Foo.bar ()  ... end
-- function Foo.bar2 () ... end
-- Foo.bar3 = lib.ondemand("Foo_extra", Foo, "bar3")
-- Foo.bar4 = lib.ondemand("Foo_extra", Foo, "bar4")
--
-- return Foo
--
-- -- Foo_extra.lua
-- local Foo = require "Foo"
-- function Foo.bar3 () ... end
-- function Foo.bar4 () ... end
--\end{codeexample}
--
-- @param filename The name of the file when extra methods are
-- located.
-- @param table The table for which the missing functions should be
-- loaded when they are accessed.
-- @param method The name of the method.
--
-- @return A function that, when called, loads the filename using
-- |require| and, then, forwards the call to the method.

function lib.ondemand(filename, table, name)
  return function(...)
       require (filename)
       return table[name] (...)
     end
end



---
-- This implements the a random number generator similar to the one
-- provided by Lua, but based on the tex.uniformdeviate primitive to
-- avoid differences in random numbers due to platform specifics.
--
-- @param l Lower bound
-- @param u Upper bound
-- @return A random number
function lib.random(l,u)
  local fraction_one = 268435456
  local r = tex.uniform_rand(fraction_one)/fraction_one
  if l and u then
    assert(l <= u)
    return math.floor(r*(u-l+1)) + l
  elseif l then
    assert(1.0 <= l)
    return math.floor(r*l) + 1.0
  else
    return r
  end
end

---
-- Provide the seed for the random number generator
--
-- @param seed random seed
function lib.randomseed(seed)
  tex.init_rand(seed)
end

-- Done

return lib