m8ta
You are not authenticated, login. 

{1574} 
ref: 0
tags: ocaml application functional programming
date: 10112022 21:36 gmt
revision:2
[1] [0] [head]


https://stackoverflow.com/questions/26475765/ocamlfunctionwithvariablenumberofarguments From this I learned that in ocaml you can return not just functions (e.g. currying) but appliations of yettobe named functions. let sum f = f 0 ;; let arg a b c = c ( b + a ) ;; let z a = a ;; then sum (arg 1) ;; is welltyped as (int > `a) > `a = <fun> e.g. an application of a function that converts int to `a. Think of it as the application of Xa to argument ( 0 + 1 ), where Xa is the argument (per type signature). Zero is supplied by the definition of 'sum'. sum (arg 1) (arg 2);; can be parsed as (sum (arg 1)) (arg 2) ;; '(arg 2)' outputs an application of an int & a yetto be determined function to 'a, E.g. it's typed as int > (int > `a) > `a = <fun>. So, you can call it Xa passed to above. Or, Xa = Xb( ( 0 + 1 ) + 2) where, again, Xb is a yettobe defined function that is supplied as an argument. Therefore, you can collapse the whole chain with the identity function z. But, of course, it could be anything else  square root perhaps for MSE? All very clever.  
{813} 
ref: work0
tags: kicadocaml zbuffer comparison picture screenshot
date: 03032010 16:38 gmt
revision:4
[3] [2] [1] [0] [head]


Simple illustration of Kicadocaml with Z buffering enabled: and disabled: I normally use it with Z buffering enabled, but turn it off if, say, I want to clearly see all the track intersections, especially colinear tracks or zero length tracks. (Probably I should write something to merge and remove these automatically.) Note that in either case, tracks and modules are rendered backtofront, which effects a Zsorting of sorts; it is the GPUs Z buffer that is enabled/disabled here.  
{812}  
Aint she pretty? More shots of the completed board (click for full resolution image):
 
{803}  
This morning i checked my bank account, and was throughly offended with what was in there. To figure out where I was spending my money, I exported a csv from the bank's website, and read it into open office to label each expense. Since I couldn't easily figure out how to sum along each label, I wrote an ocaml program to do this  ocaml let gitline ic = ( try input_line ic, false with _ > "", true ) ;; let fos = float_of_string let ios = int_of_string let soi = string_of_int let sof = string_of_float let foi = float_of_int let iof = int_of_float let fabs = abs_float let read fname = let eof = ref false in let out = ref [] in let ic = open_in fname in let tab = Str.regexp "," in while not !eof do ( let line, eoff = gitline ic in let ar = Array.of_list (Str.split tab line) in if Array.length ar = 7 then ( let debit = fos ar.(3) in let credit = fos ar.(4) in let wha = ar.(6) in out := (debit,credit,wha) :: !out ; ); eof := eoff; ) done; close_in_noerr ic ; !out ;; let _ = let sumht = Hashtbl.create 50 in List.iter (fun a > let debit,credit,wha = a in let m = try Hashtbl.find sumht wha with _ > 0.0 in let m2 = m . credit +. debit in Hashtbl.replace sumht wha m2 ) ( read "/home/tlh24/Desktop/Suntrust_History.csv"); Hashtbl.iter (fun wha valu > print_endline( wha^","^(sof valu)); ) sumht ;The first half of this file is 'stock'  just helper functions for reading in the CSV file (you can copypaste to use on your own files). After that, it's just assigning fields to variables and summing along the labels with a hash table  easy as it should be. Certainly it could be accomplished in far fewer lines with perl, but perl is not at the tip of my tongue as ocaml is now :) For the curious, here is the result (bar charts >> pie charts): I spend a lot of money on food and 'parts'. Food is pretty selfexplanatory; 'parts' includes electronic parts, bike parts (a fender, bike clips, new lights), a new cell phone, stuff from home depot. Tools was mostly for a cylinder of welding gas  you have to buy the cylinder; the gas is relatively cheap. The labels are sortof amorphous, since all are directed toward the goal of fixing my (*&^%) car, which has a rustedout crack in the frame from where the (*&^%) previous owner attached an aftermarket brace. Finally, the gas was from a 1300 mile road trip over Thanksgiving (in my other POS car, whose drivers side front wheel bearing is loose on the strut mount, oh my). Normally I don't spend that much on gas.  
{774} 
ref: work0
tags: functional programming compilation ocaml
date: 08242009 14:33 gmt
revision:0
[head]


The implementation of functional programming languages  book!  
{768}  
http://mlpost.lri.fr/  allows drawing Latex or postscript figures programmatically. Interesting. Included in Debian. source  
{764} 
ref: work0
tags: ocaml mysql programming functional
date: 07032009 19:16 gmt
revision:2
[1] [0] [head]


Foe my work I store a lot of analyzed data in SQL databases. In one of these, I have stored the anatomical target that the data was recorded from  namely, STN or VIM thalamus. After updating the analysis programs, I needed to copy the anatomical target data over to the new SQL tables. Where perl may have been my previous goto language for this task, I've had enuogh of its strange quiks, hence decided to try it in Ruby (worked, but was not so elegant, as I don't actually know Ruby!) and then Ocaml. ocaml #use "topfind" #require "mysql" (* this function takes a query and a function that converts entries in a row to Ocaml tuples *) let read_table db query rowfunc = let r = Mysql.exec db query in let col = Mysql.column r in let rec loop = function  None > []  Some x > rowfunc col x :: loop (Mysql.fetch r) in loop (Mysql.fetch r) ;; let _ = let db = Mysql.quick_connect ~host:"crispy" ~database:"turner" ~password:"" ~user:"" () in let nn = Mysql.not_null in (* this function builds a table of files (recording sessions) from a given target, then uses the mysql UPDATE command to propagate to the new SQL database. *) let propagate targ = let t = read_table db ("SELECT file, COUNT(file) FROM `xcor2` WHERE target='"^targ^"' GROUP BY file") (fun col row > ( nn Mysql.str2ml (col ~key:"file" ~row), nn Mysql.int2ml (col ~key:"COUNT(file)" ~row) ) ) in List.iter (fun (fname,_) > let query = "UPDATE `xcor3` SET `target`='"^targ^ "' WHERE STRCMP(`file`,'"^fname^"')=0" in print_endline query ; ignore( Mysql.exec db query ) ) t ; in propagate "STN" ; propagate "VIM" ; propagate "CTX" ; Mysql.disconnect db ;; Interacting with MySQL is quite easy with Ocaml  though the type system adds a certain overhead, it's not too bad.  
{758}  
Ocaml has an interactive top level, but in order to make this useful (e.g. for inspecting the types of variables, trying out code before compiling it), you need to import libraries and modules. If you have ocamlfind on your system (I think this is the requirement..), do this with: #use "topfind";; at the ocaml prompt, then #require"package names" . e.g: tlh24@chimera:~/svn/m8ta/yushin$ ledit  ocaml Objective Caml version 3.10.2 # #use "topfind";;  : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;; to load camlp4 (standard syntax) #camlp4r;; to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads  : unit = () # #require "bigarray,gsl";; /usr/lib/ocaml/3.10.2/bigarray.cma: loaded /usr/lib/ocaml/3.10.2/gsl: added to search path /usr/lib/ocaml/3.10.2/gsl/gsl.cma: loaded # #require "pcre,unix,str";; /usr/lib/ocaml/3.10.2/pcre: added to search path /usr/lib/ocaml/3.10.2/pcre/pcre.cma: loaded /usr/lib/ocaml/3.10.2/unix.cma: loaded /usr/lib/ocaml/3.10.2/str.cma: loaded # Pcre.pmatch ;;  : ?iflags:Pcre.irflag > ?flags:Pcre.rflag list > ?rex:Pcre.regexp > ?pat:string > ?pos:int > ?callout:Pcre.callout > string > bool = <fun> # let m = Gsl_matrix.create 3 3;; val m : Gsl_matrix.matrix = <abstr> # m;;  : Gsl_matrix.matrix = <abstr> # m.{1,1};;  : float = 6.94305623882282e310 # m.{0,0};;  : float = 6.94305568087725e310 # m.{1,1} < 1.0 ;;  : unit = () # m.{2,2} < 2.0 ;;  : unit = () # let mstr = Marshal.to_string m [] ;; Nice!  
{668} 
ref: notes0
tags: triangulation kicadocaml
date: 02042009 21:40 gmt
revision:7
[6] [5] [4] [3] [2] [1] [head]


PCB copper zones using triangle meshes Abstract: Many tasks in computerassisted design involve the removal of polygons from other polygons. Particularly, this problem is found when filling a region of a printed circuit board (PCB) with a polygonal zone or 'pour' of copper. This zone is attached to a net, perhaps ground, and hence other tracks, vias, and segments of copper not on the same net but within its region must be avoided by a clearance distance. This clearance can be observed by subtraction of expanded polygons from the original zone's outline polygon, as is done in two opensource PCB design softwares, Kicad and gEDA. Here we present a fast and scalable algorithm that works with triangles instead of polygons. The algorithm is able to mesh, add edges, and remove conflicting triangles within a few seconds for problems involving 10,000 points. Introduction: I have contributed, infrequently, to the opensource electronic design automation (EDA) suite Kicad for the past year or so. November/December of 2007 I added duplicated hierarchal support to Kicad's schematic editor, eeschema, which allows, like many commercial packages, duplicate instances of subschematics. This feature is used when a segment of circuitry is duplicated multiple times in a design, perhaps when there are multiple identical channels, e.g. in an audio mixer. However pcbnew (the layout editor in Kicad) is unaware of the duplication, hence for each subschematic the layout had to be duplicated. This involved a lot of work for the 8channel microstimulator board that I was working on at the time, so I decided to implement a small application to help layout an array of duplicated circuitry. Ocaml was chosen to implement the software, as I wanted to learn the language. In the course of working on PCBs, learning Ocaml, and basically scratching a series of itches, the software, tentatively named "Kicadocaml", has become progressively more featurerich, useful, and tested. It has ratsnest, DRC online and offline checking, push routing, schematic hierarchy comprehension (of course), connectivity testing, billofmaterials generation, and a responsive OpenGLbased GUI. In my last board, pcbnew failed to fill all the zones; I'm not sure why. I tried to fix the bug, but got lazy/overwhelmed after a while, and decided to just write a zonefilling algorithm from scratch myself (to scratch the itch, so to speak). Sure it's reinventing the wheel, but reinventing is fun. In the interest of documenting the algorithm a bit for posterity, the algorithm is described below. Algorithm: A list is made of all points and segments that may be involved in the zonefill. This includes, of course, the edges of the zone, as well as the outline of any track/via/pad cutout within the zone (and not of the same net number), expanded to allow for zone clearance and zoneedge stroking. The list of points also must include any intersections between segments. For efficiency, the lists of points and segments are culled by checking each polygon to be subtracted to make sure that at least one of it's points is within the zone polygon; this is done via the standard inside/outside polygon test. The list of points is then incrementally inserted into a linked triangle mesh via a very simple, very effective method of triangle splitting and edgeflipping. Linked triangle mesh means that each triangle stores a index (or pointer) to the triangle off each of its three edges. This is to facilitate the insertion of points: to find the triangle that a point is in, you walk over the linked mesh, crossing the edge between triangles that intersects a ray from the center of the present triangle to the target point. (Given the ordering of points within the list, this can be nearly a constanttime operation). See below.
Once a triangle is found, it is split into three triangles by the addition of the point. Then, each pair of triangles, one new and one old (bordering the triangle that was split) is checked to see if flipping the interior segment would increase the smallest angle. Remarkably, this reliably takes care of edge insertion  no specialized edge insertion routine was required (however, loops in the find triangle algorithm (figure 1) must be eliminated for a triangle to be found when a point is on an edge). I decided to simply maximize the minimum angle in each triangle, rather than observe the Delaunay criteria which doesn't matter for this application.
This algorithm only deals with finding containing triangles and inserting points; hence, it must be seeded with at least one triangle which will contain all others. I chose to use two triangles defined by a slightlyenlarged bounding box of all points to be inserted. The algorithm does not insure that all polygon segments are in the list of edges of a mesh; hence, after all points are inserted, every edge is checked to make sure if it is in the mesh  see figure 3.
Once all points and all edges from the original list are in the mesh, then each triangle may be tested to see if it should be kept or removed. In kicadocaml this is done with DRC (design rule check) testing.
Afterword: The algorithm runs well; it takes ~ 2 seconds to mesh, edge check, and filter 10,000 points on my Core2 2.4Ghz desktop computer. Though it was written in a higherlevel language (about 600 lines of Ocaml), I do not think that it would be hard to port to C++ for inclusion in other PCB layout packages. Great effort was not necessarily put into the design of the algorithm, but rather the numerical stability of it's subcomponents, such as the triangle insideoutside check (computed with the cross product), and the segment intersection test. For these, please see the source, or {661}.  
{661} 
ref: 0
tags: computational geometry triangulation ocaml kicadocaml zone fill edge
date: 01262009 01:47 gmt
revision:3
[2] [1] [0] [head]


I have been working hard to add zone support to kicadocaml since the implementation in kicad's PCBnew is somewhat borken (at least for my boards). It is not a very easy task! Roughly, the task is this: given a zone of copper pour, perhaps attached to the ground net, and a series of tracks, vias, and pads also on that layer of the PCB but not on the same net, form cutouts in the zone so that there is an even spacing between the tracks/vias and zone. Currently I'm attacking the problem using triangles (not polygons like the other PCB softwares). I chose triangles since I'm using OpenGL to display the PCB, and triangles are a very native mode of drawing in OpenGL. Points are added to the triangle mesh with an incremental algorithm, where the triangles are stored as a linkedmesh : each triangle has a pointer (index#) to the triangle off edge ab,bc,ca. This allows finding the containing triangle when inserting a point a matter of jumping between triangles; since many of the points to be inserted are close to eachother, this is a relatively efficient algorithm. Once the triangle containing a point to be inserted is found, the triangle is split into three, the pointers are updated appropriately, and each triangle is tested to see if flipping with it's pair would result in a net larger smallest interior angle between the two. (This is not the same as Delaunay's criteria, but it is simpler, and it produces equally beautiful pictures.) The problem is when two triangles are allowed to overlap or a gap is allowed  this makes the search algorithm die or get into a loop, and is a major major problem of the approach. In Guibas and Stolfi's paper, "Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams", they use an edge data structure, rather than a triangle data structure, which I suppose avoids this problem. I was lazy when starting this project, and chose the more obvious trianglecentric way of storing the data. The insertion of points is actually not so hard; the big problem is making sure the edges in the original list of polygons are represented in the list of edges in the triangle mesh. Otherwise, triangles will span edges, which will result in DRC violations (e.g.g copper too close to vias). My inefficient way of doing this is to calculate, for all triangles, their intersections with the polygon segments, then adding this to the mesh until all segments are represented in the list. This process, too, is prone to numerical instability. Perhaps the solution is to move back to an edgecentric data representation, so that certain edges can be 'pinned' or frozen, and hence they are guaranteed to be in the triangle mesh's edge list. I don't know; need to think about this more. Update: I got most of it working; at least the triangulation & making sure the edges are in the triangle mesh are working. Mostly there were issues with numerical precision with narrow / small triangles; I rewrote the inside triangle function to use the cross product, which helped (this seems like the simplest way, and it avoids divisions!): ocaml let insidetri a b c d = cross (sub b a) (sub d a) > 0.0 && cross (sub c b) (sub d b) > 0.0 && cross (sub a c) (sub d c) > 0.0 ;; as well as the segmentsegment intersection algorithm: ocaml let intersect a b c d = (* see if two line segments intersect *) (* return the point of intersection too *) let ab = sub b a in (* a prime is the origin *) let bp = length ab in let xx = norm ab in let yy = (1.) *. (snd xx) , (fst xx) in let project e = (dot (sub e a) xx) , (dot (sub e a) yy) in let cp = project c in let dp = project d in let cd = sub dp cp in let m = (fst cd) /. (snd cd) in let o = (fst cp) . m *. (snd cp) in let e = add (scl ab (o /. bp)) a in (* cp and dp must span the xaxis *) if ((snd cp) <= 0. && (snd dp) >= 0.)  ((snd cp) >= 0. && (snd dp) <= 0.) then ( if o >= 0. && o <= bp then ( true, e ) else ( false, e ) ) else ( false, e ) ;; Everything was very sensitive to ">" vs. ">="  all must be correct. All triangles must be CCW, too, for the inside algorithm to work  this requires that points to be inserted close to a triangle edge must be snapped to that edge to avoid any possible CW triangles. (Determining if a triangle is CW or CCW is as simple as measuring the sign of the smallest cross product between two segments). I tried, for a day or so, to include a specialized function to insert points along a triangle's edge, but that turned out not to matter; the normal flipping routine works fine. I also tried inserting auxiliary points to try to break up very small triangles, but that really didn't affect the stability of the algorithm much. It is either correct, or it is not, and my large board was a good test suite. I have, however, seeded the triangularization with a grid of (up to) 20x20 points (this depends on the aspect ratio of the region to be filled  the points are equally spaced in x and y). This adds (max) 800 triangles, but it makes the algorithm more stable  fewer very narrow triangles  and we are working with sets of 10,000 triangles anyway for the large zones of copper. Some corrections remain to be done regarding removing triangles based on DRC violation and using the linkedmesh of triangles when calculating edgetriangle edge intersection, but that should be relatively minor. Now I have to figure out how to store it in Kicad's ".brd" file format. Kicad uses "Kbool" library for intersection polygons  much faster than my triangle methods (well, it's in C not ocaml)  and generates concave polygons not triangles. Would prefer to do this so that I don't have to reimplement gerber export. (Of course, look at how much I have reimplemented! This was originally a project just to learn ocaml  Well, gotta have some fun :)  
{590}  
It is not obvious how to run an external command in ocaml & get it's output from stdin. Here is my hack, which simply polls the output of the program until there is nothing left to read. Not very highly tested, but I wanted to share, as I don't think there is an example of the same on pleac let run_command cmd = let inch = Unix.open_process_in cmd in let infd = Unix.descr_of_in_channel inch in let buf = String.create 20000 in let il = ref 1 in let offset = ref 0 in while !il > 0 do ( let inlen = Unix.read infd buf !offset (20000 !offset) in il := inlen ; offset := !offset + inlen; ) done; ignore(Unix.close_process_in inch); if !offset = 0 then "" else String.sub buf 0 !offset ;; Note: Fixed a nasty stringtermination/memoryreuse bug Sept 10 2008  
{576}  
why do threads suck in ocaml? because join calculus is better! (well maybe) http://jocaml.inria.fr/ example of jocaml working well (indeed, faster than everything else): http://eigenclass.org/hiki/widefinderconclusions  
{567}  
Ocaml books / references:
 
{550}  
cairoocaml is broken in Debian (lenny) in that it is incompatible with liblablgtk2 in the repository; to compile ocaml programs (e.g. Geoproof) that depend on it, you need to :
 
{536}  
