diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua')
-rw-r--r-- | Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua new file mode 100644 index 00000000000..dcfb468d063 --- /dev/null +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua @@ -0,0 +1,356 @@ +-- 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: /cvsroot/pgf/pgf/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua,v 1.5 2013/04/04 20:43:45 tantau Exp $ + + + +--- +-- 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 = math.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 drawin/foo| has an inital 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 exsist. 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 inheritence, if necessary + if not getmetatable(t) then + setmetatable(t, t.base_class) + end + + return t +end + + +-- Done + +return lib
\ No newline at end of file |