Okay, they aren't _real_ perceptrons, but fancy parameterized trees connected on a hex grid, coded with MetaFun and Lua.
Big version: https://pdfhost.io/v/piuN04dSq_perceptron If anyone is interested in the full source code, let me know. I couldn't get "angle" to work properly. Hans, your simplifications on the atantwo function also didn't work for all cases. There was a single edge case that didn't determine the correct angle. Don't know why. Cheers!
perceptron-01.pdf
Description: Adobe PDF document
perceptron-02.pdf
Description: Adobe PDF document
\definecolor[HexGridBase][h=E0E0E0] \definecolor[HexGridNode][h=202020] \definecolor[HexGridEdge][h=808080] %\definecolor[HexGridBase][h=1f50da] %\definecolor[HexGridNode][h=00d687] %\definecolor[HexGridEdge][h=00d687] \startluacode require "Graph" -- Try to generate a different tree each run. math.randomseed( math.modf( os.clock() * 10000000 ), os.time() ) userdata = userdata or {} ud = userdata -- Create a minimally spanning acyclic graph that's mostly connected. -- -- @param r - numeric - The number of rows -- @param c - numeric - The number of columns -- @param m - numeric The number of edges -- -- @return A handle to the tree instance. function tree( r, c, m ) local graph = Graph:new() local edges = graph:connected( r, c, m ) local source = edges[ math.random( #edges ) ] local tree = graph:compute( source ) return tree end -- Extract the first pair of a vertex at the given index inside the tree. -- No error checking is performed. -- -- @param graph - object - The tree containing numerous edges. -- @param index - non-negative integer - The index for the vertex pair. -- -- @return The (x, y) pair for the first vertex comprising an edge. function ud.vertex_a( graph, index ) u = graph[ index ].u return { u.x, u.y } end -- Extract the second pair of a vertex at the given index inside the tree. -- No error checking is performed. -- -- @param graph - object - The tree containing numerous edges. -- @param index - non-negative integer - The index for the vertex pair. -- -- @return The (x, y) pair for the second vertex comprising an edge. function ud.vertex_b( graph, index ) v = graph[ index ].v return { v.x, v.y } end -- Return the number of edges in the tree. -- -- @param graph - object - The tree containing numerous nodes. -- -- @return The number of vertex pairs in the tree. function ud.count( graph ) return #graph end \stopluacode \startuseMPgraphic{HexGridBaseGraphic}{side} % Set the random seed to the current second. randomseed := lua( "os.time()" ); vardef atantwo( expr ax, ay, bx, by ) = save theta; dx := bx - ax; dy := by - ay; theta := 0; if (dx > 0): theta := atan( dy / dx ); elseif (dx < 0) and (dy >= 0): theta := atan( dy / dx ) + pi; elseif (dx < 0) and (dy < 0): theta := atan( dy / dx ) - pi; elseif (dx == 0) and (dy > 0): theta := pi / 2; elseif (dx == 0) and (dy < 0): theta := -pi / 2; fi; theta enddef; vardef degrees( expr rad ) = rad * 180 / pi enddef; vardef distance( expr ax, ay, bx, by ) = sqrt( ((bx - ax)^2) + ((by - ay)^2) ) enddef; % Set the number of hexagons from top to bottom. GRID_C = 124; % Set the number of hexagons from left to right. GRID_R = 120; % Set the number of pathways between nodes (higher is more complexity). PATHWAYS = 235; % Grid zoom level (smaller is further away). SCALE = 5; % Hexagon dimensions. HEIGHT = sqrt( 3 ); HHEIGHT = HEIGHT / 2; WIDTH = 2; color colour_base; color colour_node; color colour_edge; colour_base = \MPcolor{HexGridBase}; colour_node = \MPcolor{HexGridNode}; colour_edge = \MPcolor{HexGridEdge}; % Vertex diameters proportional to the hexagon height. vertex_sm := HEIGHT / 12; vertex_lg := HEIGHT / 5; path path_ul; path path_ur; path path_tp; path_ur := dir( 60 * 0 ) -- dir( 60 * 1 ); path_tp := dir( 60 * 1 ) -- dir( 60 * 2 ); path_ul := dir( 60 * 2 ) -- dir( 60 * 3 ); picture hexgrid; picture vertices; picture perceptrons; picture connections; hexgrid := nullpicture; vertices := nullpicture; perceptrons := nullpicture; connections := nullpicture; % Line width. pickup pencircle scaled .05bp; addto hexgrid also image( for c = 1 upto GRID_C: for r = 1 upto GRID_R: offset_c := c * 3 / WIDTH; offset_r := r * HEIGHT - (c mod 2 * HHEIGHT); draw path_ul shifted (offset_c, offset_r) withcolor colour_base; draw path_tp shifted (offset_c, offset_r) withcolor colour_base; draw path_ur shifted (offset_c, offset_r) withcolor colour_base; for i = 0 upto 2: addto vertices also image( draw point i of path_tp shifted (offset_c, offset_r) withcolor colour_base withpen pencircle scaled vertex_sm; ); endfor; endfor; endfor; ); % Create the perceptron matrix. lua( "ud.graph = tree( " & decimal( GRID_C ) & ", " & decimal( GRID_R ) & ", " & decimal( PATHWAYS ) & ")" ); edges := lua( "ud.count( ud.graph )" ); for i := 1 upto edges: lua( "va = ud.vertex_a( ud.graph, " & decimal( i ) & ")" ); lua( "vb = ud.vertex_b( ud.graph, " & decimal( i ) & ")" ); vac := lua( "va[1]" ); var := lua( "va[2]" ); vbc := lua( "vb[1]" ); vbr := lua( "vb[2]" ); offset_ac := vac * 3 / WIDTH; offset_ar := var * HEIGHT - (vac mod 2 * HHEIGHT); offset_bc := vbc * 3 / WIDTH; offset_br := vbr * HEIGHT - (vbc mod 2 * HHEIGHT); % Draw a large nodes at the starting/ending coordinates. addto perceptrons also image( draw (offset_ac, offset_ar) withcolor colour_node withpen pencircle scaled vertex_lg; draw (offset_bc, offset_br) withcolor colour_node withpen pencircle scaled vertex_lg; ); addto perceptrons also image( numeric vangle; numeric vc; numeric vr; numeric sc; numeric sr; vi := round( degrees( atantwo( vac, var, vbc, vbr ) ) / 60 ); % Compute direction towards the first segment (to vertex of an edge). vangle := vi * 60 * pi / 180; % Calculate the position of the first vertex, offset from the center. vc := offset_ac + cos( vangle ); vr := offset_ar + sin( vangle ); % Draw a line from the starting point to the subsequent vertex. addto connections also image( draw (offset_ac, offset_ar) -- (vc, vr) withcolor colour_edge; ); iterations := 1; forever: % Draw a circle at the subsequent vertex. draw (vc, vr) withcolor colour_node withpen pencircle scaled if round( uniformdeviate( 3 ) ) = 0: vertex_lg else: vertex_sm; fi; % 2 _ 1 % 3 / \ 0 % -2 \_/ -1 % % Determine the next vertex based on smallest angle of the % three possible vertices with respect to the line. start := if (vi mod 2) == 1: -1 else: -2 fi; % Ensure that at least one vertex will be selected. nearest := infinity; for k = start step 2 until 3: kangle := k * 60 * pi / 180; nc := vc + cos( kangle ); nr := vr + sin( kangle ); d := distance( offset_bc, offset_br, nc, nr ); if d < nearest: nearest := d; sc := nc; sr := nr; vi := k + 1; fi; endfor; d := distance( offset_bc, offset_br, sc, sr ); iterations := iterations + 1; if (d <= 1) and (iterations > 2) and (iterations mod 2 = 0): draw (sc, sr) withcolor colour_node withpen pencircle scaled vertex_sm; fi; exitif (d <= 1); addto connections also image( draw (vc, vr) -- (sc, sr) withcolor colour_edge withpen pencircle scaled 0.05bp; ); vc := sc; vr := sr; endfor; if (d < 1) and (iterations > 2): draw (sc, sr) withcolor colour_node withpen pencircle scaled vertex_sm; fi; addto connections also image( draw (offset_bc, offset_br) -- (vc, vr) withcolor colour_edge withpen pencircle scaled 0.05bp; ); ); endfor; draw hexgrid scaled SCALE; draw vertices scaled SCALE; draw connections scaled SCALE; draw perceptrons scaled SCALE; \stopuseMPgraphic \startuseMPgraphic{HexGridBgGraphic} % Define the grid background colour color gridback; gridback := (0.15, 0.18, 0.24); fill unitsquare xyscaled (OverlayWidth, OverlayHeight) withcolor gridback; \stopuseMPgraphic \defineoverlay[HexGridBaseGraphic][\uniqueMPgraphic{HexGridBaseGraphic}] \defineoverlay[HexGridBgGraphic][\uniqueMPgraphic{HexGridBgGraphic}] \setupbackgrounds[page][background={HexGridBaseGraphic}] \starttext \startalignment[middle] \color[white]{GRID} \stopalignment \stoptext
___________________________________________________________________________________ If your question is of interest to others as well, please add an entry to the Wiki! maillist : ntg-context@ntg.nl / https://www.ntg.nl/mailman/listinfo/ntg-context webpage : https://www.pragma-ade.nl / http://context.aanhet.net archive : https://bitbucket.org/phg/context-mirror/commits/ wiki : https://contextgarden.net ___________________________________________________________________________________