File Coverage

blib/lib/PDL/Fit/Levmar/Func.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             #
2             # GENERATED WITH PDL::PP from func.pd! Don't modify!
3             #
4             package PDL::Fit::Levmar::Func;
5              
6             our @EXPORT_OK = qw(levmar_func _callf _callj _callj1 );
7             our %EXPORT_TAGS = (Func=>\@EXPORT_OK);
8              
9 8     8   132823 use PDL::Core;
  8         38919  
  8         59  
10 8     8   2821 use PDL::Exporter;
  8         17  
  8         50  
11 8     8   257 use DynaLoader;
  8         16  
  8         1800  
12              
13              
14             our $VERSION = '0.0103';
15             our @ISA = ( 'PDL::Exporter','DynaLoader' );
16             push @PDL::Core::PP, __PACKAGE__;
17             bootstrap PDL::Fit::Levmar::Func $VERSION;
18              
19              
20              
21              
22              
23              
24              
25              
26             #line 9 "func.pd"
27              
28             =head1 NAME
29              
30             PDL::Fit::Levmar::Func - Create model functions for Levenberg-Marquardt fit routines
31              
32             =head1 DESCRIPTION
33              
34             This module creates and manages functions for use with the
35             Levmar fitting module. The functions are created with a
36             very simple description language (that is mostly C), or are
37             pure C, or are perl code. For many applications, the present
38             document is not necessary because levmar uses the
39             Levmar::Func module transparantly. Therefore, before
40             reading the following, refer to L.
41              
42             =head1 SYNOPSIS
43              
44             use PDL::Fit::Levmar::Func;
45              
46             $func = levmar_func( FUNC => # define and link function
47              
48             '
49             function gaussian
50             loop
51             x[i] = p[0] * exp(-(t[i] - p[1])*(t[i] - p[1])*p[2]);
52             end function
53              
54             jacobian jacgaussian
55             double arg, expf;
56             loop
57             arg = t[i] - p[1];
58             expf = exp(-arg*arg*p[2]);
59             d0 = expf;
60             d1 = p[0]*2*arg*p[2]*expf;
61             d2 = p[0]*(-arg*arg)*expf;
62             end jacobian
63             '
64             );
65              
66             $hout = PDL::Fit::Levmar::levmar($p,$x,$t, # fit the data
67             FUNCTION => $func,
68             );
69              
70             =head1 FUNCTIONS
71              
72             =head2 levmar_func()
73              
74             =for usage
75              
76             levmar_func( OPTIONS )
77              
78             =for ref
79              
80             This function creates and links a function, ie, takes a function definition
81             and returns a function (object instance) ready for use by levmar.
82             see PDL::Fit::Levmar::Func for more information.
83              
84             OPTIONS:
85              
86             =for options
87              
88             Some of the options are described in the PDL::Fit::Levmar documentation.
89              
90             MKOBJ -- command to compile source into object code. This can be set.
91             The default value is determined by the perl installation and can
92             be determined by examining the Levmar::Func object returned by
93             new or the output hash of a call to levmar. A typical value is
94             cc -c -O2 -fPIC -o %o %c
95              
96             MKSO -- command to convert object code to dynamic library code. A typical
97             default value is
98             cc -shared -L/usr/local/lib -fstack-protector %o -o %s
99            
100              
101             CTOP -- The value of this string will be written at the top of the c code
102             written by Levmar::Func. This can be used to include headers and so forth.
103             This option is actually set in the Levmar::Func object.
104              
105             =head2 call()
106              
107             =for ref
108              
109             Call (evaluate) the fit function in a Levmar::Func object.
110              
111             =for usage
112              
113             use PDL::Fit::Levmar::Func;
114              
115             $Gh = levmar_func(FUNC=>$fcode);
116              
117             $x = $Gh->call($p,$t);
118              
119             Here $fcode is a function definition (say lpp code). (This does
120             not currently work with perl subroutines, I think. Of course,
121             you can call the subroutine directly. But it would be good
122             to support it for consistency.)
123            
124             $p is a pdl or ref to array of parameters.
125             $t is a pdl of co-ordinate values.
126             $x is the fit function evaluated at $p and $t. $x has the
127             same shape as $t.
128              
129             =for example
130              
131             $Gf = levmar_func( FUNC => '
132             function
133             x = p0 * t * t;
134             ');
135              
136             print $Gf->call([2],sequence(10)) , "\n";
137             [0 2 8 18 32 50 72 98 128 162]
138              
139             =cut
140              
141             use strict;
142             use Carp;
143             use Config;
144             use File::Path;
145             use File::Spec::Functions;
146              
147             sub munlink;
148              
149             #use PDL::NiceSlice;
150             use PDL::Core ':Internal'; # For topdl()
151              
152             use vars ('$MKOBJ', '$MKSO', '$OBJ_EXT' , '$SO',
153             '$LEVFUNC', '$JLEVFUNC', '$LPPEXT' );
154              
155             # These are pointers to the C functions that wrap the user's
156             # perl fit functions.
157             #$LEVFUNC = get_perl_func_wrap();
158             #$JLEVFUNC = get_perl_jac_wrap();
159              
160             $OBJ_EXT = $Config{obj_ext};
161             $SO = $Config{so};
162             $LPPEXT = '.lpp';
163             # string to compile .c to .o
164             $MKOBJ = $Config{cc} . " -c " . $Config{optimize} . " " .
165             $Config{cccdlflags} . " -o %o %c ";
166              
167             # string to compile .o to .so
168             $MKSO = $Config{ld} . " " . $Config{lddlflags} ." %o -o %s ";
169              
170             use File::Temp qw(tempdir);
171              
172             #line 181 "func.pd"
173              
174             =head2 new
175              
176             =for usage
177              
178             my $fitfunc = new PDL::Fit::Levmar::Func(...);
179             or
180             my $fitfunc = levmar_func(...);
181              
182             =for ref
183              
184             Generic constructor. Use levmar_func rather than new.
185              
186             =cut
187              
188             $PDL::Fit::Levmar::Func::SRC_EXT = ".c";
189             #$PDL::Fit::Levmar::Func::SO_EXT = ".so";
190             #$PDL::Fit::Levmar::Func::OBJ_EXT = ".o";
191              
192             sub deb {
193             # print STDERR $_[0], "\n";
194             }
195              
196             sub prwarn { print STDERR $_[0], "\n";}
197              
198             ##########################################
199             # Methods follow
200              
201             # some kind of stack corruption is related to this function, maybe. no probably not.
202             # So, only shift opts if they are there
203             #use Data::Dumper;
204              
205             sub new {
206             my($class) = shift;
207             my($opts) = shift;
208             # print STDERR "In new class: $class, opts $opts\n";
209             if(ref $opts ne 'HASH') { # change opts to hash of opts
210             $opts = defined $opts ? {$opts,@_} : {} ;
211             }
212             # print Dumper($opts),"\n";
213             my $self = { # following are defaults
214             MKOBJ => $MKOBJ,
215             MKSO => $MKSO,
216             NOCLEAN => undef,
217             FUNC => undef,
218             JFUNC => undef,
219             # TYPE => 'double',
220             NOSO => undef,
221             CSRC => undef,
222             CTOP => undef,
223             DIR => tempdir( CLEANUP => !$opts->{NOCLEAN} ), # where the .so is built
224             TESTSYNTAX => undef,
225             LIBHANDLE => undef,
226             FVERBOSE => 0,
227             };
228             foreach ( keys %$opts ) { # replace defaults
229             if ( exists $self->{$_} ) {
230             $self->{$_} = $opts->{$_};
231             }
232             else { die "Levmar::Func::new: Unrecognized option to Levmar::Func '$_'";}
233             }
234             return bless $self,$class;
235             }
236              
237             # all these attempts at dying and croaking fail.
238             # program does not quit and error messages are not printed
239             # dont know why. It must be some bad bug in the xs code.
240             # If I just print the error message, its fine.
241             # I think it has to do with DESTROY. return does not work either
242             sub DESTROY {
243             my $self = shift;
244             my $cnt = 0;
245             return if defined $self->{NOSO};
246             if ( defined $self->{LIBHANDLE}) {
247             my ($ret, $err) = close_shared_object_file($self->{LIBHANDLE});
248             if ( $err ne '' or $ret != 0) {
249             warn "Levmar::Func::DESTROY: Error closing function library:$ret '$err'";
250             }
251             warn "Error closing function library:$ret '$err'" if $ret != 0;
252             if ( defined $self->{JPOINTER} ) { # call close twice because we got two symbols
253             ($ret, $err) = close_shared_object_file($self->{LIBHANDLE});
254             warn "Error closing function library:$ret '$err'" if $ret !=0 ;
255             if ( $err ne '' or $ret != 0 ) {
256             warn "Levmar::Func::DESTROY: Error closing function library:$ret '$err'";
257             }
258             }
259             if ( defined $self->{SJPOINTER} ) { # call close twice because we got two symbols
260             ($ret, $err) = close_shared_object_file($self->{LIBHANDLE});
261             warn "Error closing function library:$ret '$err'" if $ret !=0 ;
262             if ( $err ne '' or $ret != 0 ) {
263             warn "Levmar::Func::DESTROY: Error closing function library:$ret '$err'";
264             }
265             }
266             if ( defined $self->{SFPOINTER} ) { # call close twice because we got two symbols
267             ($ret, $err) = close_shared_object_file($self->{LIBHANDLE});
268             warn "Error closing function library:$ret '$err'" if $ret !=0 ;
269             if ( $err ne '' or $ret != 0 ) {
270             warn "Levmar::Func::DESTROY: Error closing function library:$ret '$err'";
271             }
272             }
273             }
274             if (not defined $self->{NOCLEAN} and defined $self->{SONAME} ) {
275             foreach my $k ( qw ( SONAME )) { # clean so file
276             my $fn = $self->{$k};
277             if (-e $fn) {
278             if ( not -f $fn ) {
279             warn "Levmar::Func::DESTROY: Refusing to remove non-file '$fn'";
280             }
281             else {
282             $cnt = munlink $fn;
283             if ( $cnt < 1 ) {
284             warn "Levmar::Func::DESTROY: failed removing '$fn' (lib probably open)";
285             }
286             else {
287             # warn "Levmar::Func::DESTROY: SUCCESS removing '$fn'";
288             }
289             }
290             }
291             }
292             }
293             }
294              
295             sub levmar_func { my $self = new PDL::Fit::Levmar::Func(@_);
296             my @err;
297             if ( defined $self->{FUNC} and $self->{FUNC} =~ /CODE/ ) {
298             $self->{NOSO} = 1; # bad way to handle this
299             $self->{FPOINTER} = 0; # test for this in levmar
300             }
301             else {
302             if ( not defined $self->{FUNC} and not defined $self->{CSRC} ) {
303             die "Levmar::Func::lemar_func: neither FUNC nor CSRC defined";
304             }
305             @err = $self->make_ccode();
306             return @err if $err[0] == -1;
307             $self->make_build_names();
308             $self->write_ccode();
309             if ( not $self->make_shared_object_file() ) {
310             die "Levmar::Func::levmar_func: Compilation failed.";
311             }
312             if ( not $self->load_fit_library() ) {
313             die "Levmar::Func::levmar_func: Loading dynamic library failed.";
314             }
315             $self->clean_files() unless defined $self->{NOCLEAN};
316             }
317             if ( defined $self->{JFUNC} ) { # probably won't get called
318             if ( $self->{JFUNC} =~ /CODE/ ) {
319             $self->{NOSO} = 1;
320             }
321             else {
322             die "Levmar::Func::levmar_func option JFUNC must be a ref to a perl sub";
323             }
324             }
325             return $self;
326             }
327              
328             sub make_build_names {
329             my $self = shift;
330             die "Levmar::Func::levmar_func: no name for function"
331             unless defined $self->{NAME};
332             my $q = $self->{DIR};
333             if ( not -d $q ) {
334             die "Levmar::Func::levmar_func: Can't make directory (folder) '$q'"
335             unless File::Path::mkpath( $q );
336             }
337             $self->{FNAME} = $self->{NAME} unless exists $self->{FNAME}; # base file name
338             my $n = $self->{FNAME};
339             my $srcn = catfile( $q , $n . $PDL::Fit::Levmar::Func::SRC_EXT);
340             my $son = catfile($q ,$n . "." . $SO);
341             my $objn = catfile($q , $n . $OBJ_EXT);
342             $self->{SRCNAME} = $srcn;
343             $self->{SONAME} = $son;
344             $self->{OBJNAME} = $objn;
345             }
346              
347             # change this to identity, can remove sometime
348             sub mfqp {
349             my ($self,$key) = @_;
350             return $self->{$key};
351             }
352              
353             # substitue string $new for $old when it
354             # occurs after 'void'.
355             sub subst_func_name {
356             my ($sref,$old,$new) = @_;
357             $$sref =~ s/(\W)void\s+$old/$1void $new/;
358             }
359              
360             # Write c source file from function definition.
361             # Entire definition is given as a string, or the
362             # filename , ending in $LPPEXT is given
363             # Copying the source strings around, inefficient. should use
364             # refs
365             sub make_ccode {
366             my $self = shift;
367             my @err;
368              
369             if ( not defined $self->{CSRC} ) { # is FUNC really c code?
370             if (not $self->{FUNC} =~ /$LPPEXT$/o # is not a $LPPEXT file
371             and ( $self->{FUNC} =~ /\.c$/ or # is a .c file
372             # doesnt have function def
373             not $self->{FUNC} =~ /(^|\n)\s*function(\s+\w+|\s*)\n/) ) {
374             $self->{CSRC} = $self->{FUNC};
375             }
376             }
377             if ( defined $self->{CSRC} ) {
378             if ( $self->{CSRC} =~ /\.c$/ ) {
379             my $cf = $self->{CSRC};
380             local (*CHAND);
381             local $/;
382             open CHAND, "<$cf" or die "Levmar::Func::make_code : Can't open C src file '$cf'";
383             $self->{CCODE} = ;
384             close(CHAND);
385             }
386             else { # inefficient, but it works
387             $self->{CCODE} = $self->{CSRC};
388             }
389             my ($funcname, $jacname) = $self->get_funcs_from_c();
390             $jacname = '' unless defined $jacname;
391             my ($sfuncname, $sjacname);
392             $sfuncname = 's' . $funcname;
393             $sjacname = 's' . $jacname if $jacname;
394             my $doublecode = $self->{CCODE};
395             my $floatcode = $doublecode;
396             subst_func_name(\$floatcode, $funcname, $sfuncname);
397             subst_func_name(\$floatcode, $jacname, $sjacname) if $jacname;
398             if ($^O =~ /MSWin32/i) {
399             my $export = ' __declspec (dllexport) ';
400             subst_func_name(\$doublecode, $funcname, $export . $funcname);
401             subst_func_name(\$floatcode, $sfuncname, $export . $sfuncname);
402             subst_func_name(\$doublecode, $jacname, $export . $jacname) if $jacname;
403             subst_func_name(\$floatcode, $sjacname, $export . $sjacname) if $jacname;
404             }
405             # if ( /^\s*void\s+([\w]+)/ )
406             $self->{CCODE} =
407             "
408             #define FLOAT double
409             " . $doublecode .
410             "
411             #undef FLOAT
412             #define FLOAT float
413             " . $floatcode;
414             $self->{NAME} = $funcname unless exists $self->{NAME};
415             $self->{JACNAME} = $jacname unless exists $self->{JACNAME};
416             return (1); # don't use FUNC even if its there.
417             }
418             elsif ( defined $self->{FUNC} ) {
419             my $st = $self->{FUNC};
420             if ($st =~ /$LPPEXT$/o) { # file, not string
421             local (*FUNCHAND);
422             local $/;
423             open FUNCHAND, "<$st" or die "Levmar::Func::make_ccode : Can't open def file '$st'";
424             $st = ;
425             close(FUNCHAND);
426             }
427             my ($funcname,$jacname,$ccode);
428             my @ret = generate_C_source($self, $st);
429             if ( $ret[0] eq '-1' ) { # stop warnings with ==
430             my $r;
431             # ($r, $funcname, $jacname, $code, @err) = @ret;
432             return @ret;
433             }
434             else {
435             ($funcname,$jacname,$ccode) = @ret;
436             }
437             $self->{CCODE} = $ccode;
438             $self->{NAME} = $funcname unless exists $self->{NAME};
439             $self->{JACNAME} = $jacname unless exists $self->{JACNAME};
440             return (1);
441             }
442             return (-1, "Can't make C code with no defintion or source file");
443             }
444              
445             # jacobian function name **must** start with 'jac' if using pure c code
446             sub get_funcs_from_c {
447             my $self = shift;
448             my @lines = split ("\n",$self->{CCODE});
449             my ($fname, $jacname) = (undef, undef);
450             foreach (@lines ) {
451             if ( /^\s*void\s+([\w]+)/ ) { # prototype begins with 'void' return type
452             my $fn = $1;
453             if ($fn =~ /^jac/ ) {
454             $jacname = $fn;
455             }
456             else {
457             $fname = $fn;
458             }
459             }
460             }
461             if ( not defined $fname or $fname eq '' ) { # ok if jacname == undef
462             die "Levmar::Func::get_funcs_from_c : Can't find function name from c code";
463             }
464             return ($fname, $jacname);
465             }
466              
467             sub write_ccode {
468             my $self = shift;
469             local (*CCODEH);
470             return unless exists $self->{CCODE};
471             if ( not defined $self->{NAME} ) {
472             die "Levmar::Func::write_ccode : Can't write C code for function with no name";
473             }
474             my $srcn = $self->{SRCNAME};
475             open CCODEH, ">$srcn" or die "Levmar::Func::write_ccode : Can't open C source file '$srcn' for writing";
476             print CCODEH $self->{CTOP}, "\n" if defined $self->{CTOP};
477             print CCODEH $self->{CCODE};
478             close CCODEH;
479             }
480              
481             sub make_shared_object_file {
482             my $self = shift;
483             my $ret;
484             my $srcn1 = $self->{SRCNAME};
485             my $fname1 = $self->{FNAME};
486             my $i = 0;
487             my $max = 20; # allow $max renamed files
488             while ( -f $self->{SONAME} ) { # this is important to avoid user side bugs
489             $i++;
490             my $so = $self->{SONAME};
491             $self->{FNAME} = $fname1 . $i;
492             $self->make_build_names();
493             # warn "Levmar::Func::make_shared_object_file: $so exists. Trying " . $self->{SONAME};
494             last if $i > $max;
495             }
496             my $srcn = $self->{SRCNAME};
497             my $objn = $self->{OBJNAME};
498             my $sobjn = $self->{SONAME};
499             my $fname = $self->{FNAME};
500             if ( $i > $max ){
501             die 'Levmar::Func::make_shared_object_file: Too many renamed files in '. $self->{DIR} . ' try cleaning.';
502             }
503             elsif ($i > 0) {
504             if ( rename($srcn1,$srcn) == 0 ) {
505             die "Levmar::Func::make_shared_object_file: Faile to rename $srcn1 to $srcn";
506             }
507             }
508             # my $mkobjstr = $self->{MKOBJ} ." -o $objn $srcn";
509             my $mkobjstr = $self->{MKOBJ};
510             $mkobjstr =~ s/\%c/$srcn/g;
511             $mkobjstr =~ s/\%o/$objn/g;
512             $ret = do_system($mkobjstr, $self); # compile c to o
513             deb "Levmar::Func::make_shared_object_file: compile returned '$ret'";
514             if ( $ret != 0) { # zero is success
515             warn "Levmar::Func::make_shared_object_file: Compiling '$srcn' failed.";
516             return 0;
517             }
518             $self->{MKOBJSTR} = $mkobjstr;
519             my $sostr = $self->{MKSO};
520             $sostr =~ s/\%s/$sobjn/g;
521             $sostr =~ s/\%o/$objn/g;
522             $ret = do_system($sostr, $self); # make so from o
523             deb "Levmar::Func::make_shared_object_file: '$sostr' make so from o returned '$ret'";
524             if ( 0 != $ret ) {
525             warn "Levmar::Func::make_shared_object_file: Making shared library '$sobjn' failed.";
526             return 0;
527             }
528             $self->{SOSTR} = $sostr;
529             }
530              
531             #### Some methods to return information
532             # get compiler strings
533             sub get_cc_str {
534             my $self = shift;
535             return ($self->{MKOBJSTR}, $self->{SOSTR});
536             }
537              
538             sub get_fpoint {
539             my $self = shift;
540             $self->{FPOINTER};
541             }
542              
543             sub get_jacpoint {
544             my $self = shift;
545             $self->{JPOINTER};
546             }
547              
548             sub get_fit_pointers {
549             my $self = shift;
550             ($self->{FPOINTER},
551             $self->{SFPOINTER},
552             $self->{JPOINTER},
553             $self->{SJPOINTER});
554             }
555              
556             sub get_file_names {
557             my $self = shift;
558             return ($self->mfqp('SRCNAME'),
559             $self->mfqp('OBJNAME'),
560             $self->mfqp('SONAME'));
561             }
562              
563             # remove generated o, and C files
564             # Well, don't remove so file.
565             sub clean_files {
566             my $self = shift;
567             my $cnt = 0;
568             my $srcn = $self->mfqp('SRCNAME'); # fully qualified names
569             my $objn = $self->mfqp('OBJNAME');
570             foreach my $k ( qw ( OBJNAME )) { # soname needs to be there
571             my $fn = $self->mfqp($k);
572             if (-e $fn) {
573             if ( not -f $fn ) {
574             warn "Levmar::Func::clean_files : Object file '$fn' not a file. Not deleting";
575             }
576             else {
577             $cnt = munlink $fn;
578             if ( $cnt < 1) {
579             warn "Levmar::Func::clean_files : cnt $cnt: Failed to delete object file '$fn'";
580             }
581             }
582             }
583             }
584             if ( -e $srcn ) {
585             if ( not -f $srcn ) {
586             warn "Levmar::Func::clean_files: Source file '$srcn' not a file. Not deleting";
587             }
588             open my $srch , '<' ,
589             $srcn or die "Levmar::Func::clean_files : Can't open C source file '$srcn' for reading";
590             my $closed = 0;
591             # weird stack bug present when using implicit $_ rather than $line.
592             # A function that calls levmar_func sometimes has an item in arg stack
593             # replaced by the first line read here.
594             while (my $line = <$srch>) {
595             next if $line =~ /^\s*$/;
596             if ($line =~ /\/\* This file automatically/) {
597             close($srch);
598             $closed = 1;
599             $cnt = 0;
600             $cnt = munlink $srcn;
601             warn "Levmar::Func::clean_files: cnt $cnt: Failed to delete source file '$srcn'"
602             if $cnt < 1;
603             last;
604             }
605             last; # only check up to first non-blank line
606             }
607             close($srch) unless $closed == 1;
608             }
609             }
610              
611             # Improve effiency after this is well tested by getting all four
612             # symbols at once.
613              
614             sub load_fit_library {
615             my $self = shift;
616             my $so = $self->mfqp('SONAME');
617             my $fn = $self->{NAME};
618             my $jn = $self->{JACNAME};
619             die "Levmar::Func::load_fit_library : Can't find dynamic library file '$so'" unless -e $so;
620             my ($func_pointer, $jac_pointer, $lib_handle, $error_message)=
621             (0,0,0,0);
622             my ($sfunc_pointer, $sjac_pointer) = # single precision
623             (0,0);
624             ($func_pointer, $lib_handle, $error_message) =
625             open_and_find($so,$fn);
626             ($sfunc_pointer, $lib_handle, $error_message) = # single precision
627             open_and_find($so,'s'.$fn);
628             if ( $error_message ne '' ) {
629             warn "Levmar::Func::load_fit_library: Failed to load dynamic library '$so'\n".
630             " and find fit func '$fn'.\n dlopen:'$error_message'";
631             return 0;
632             }
633             if ( defined $jn and $jn ne '') {
634             ($jac_pointer, $lib_handle, $error_message) =
635             open_and_find($so,$jn);
636             if ( $error_message ne '' ) {
637             warn "Levmar::Func::load_fit_library: Failed to load dynamic library '$so' and find jacobian '$jn'.\n".
638             " dlopen:'$error_message' ";
639             }
640             else {
641             $self->{JPOINTER} = $jac_pointer;
642             }
643             ($sjac_pointer, $lib_handle, $error_message) =
644             open_and_find($so, 's' . $jn);
645             if ( $error_message ne '' ) {
646             warn "Levmar::Func::load_fit_library: Failed to load dynamic library '$so' and find jacobian '$jn'.\n".
647             " dlopen:'$error_message' ";
648             }
649             else {
650             $self->{SJPOINTER} = $sjac_pointer;
651             }
652              
653             }
654             $self->{FPOINTER} = $func_pointer;
655             $self->{SFPOINTER} = $sfunc_pointer;
656             $self->{LIBHANDLE} = $lib_handle;
657             }
658              
659             # End of methods
660             # (Actually there are some more methods near the bottom
661             # that are close to the corresponding pp_defs)
662             ########################################
663             # Non-methods below here
664              
665             # should return 0 on success
666             sub do_system {
667             my ($c,$f) = @_;
668             print STDERR $c,"\n" if $f->{FVERBOSE};
669             system $c;
670             }
671              
672             sub munlink {
673             my $f = shift;
674             my $cnt;
675             my $sf = "'$f'";
676             if ( not -e $f ) {
677             prwarn "munlink: $sf does not exist";
678             return 0;
679             }
680             if ( not -f $f ) {
681             prwarn "munlink: $sf is not a file. Not removing.";
682             return 0;
683             }
684             $cnt = unlink $f;
685             if (not $cnt > 0) {
686             prwarn "munlink: Can't unlink exisiting file $sf";
687             }
688             return $cnt;
689             }
690              
691             # Turn a function description into C source
692             # !care! I disabled NiceSlice, because it erroneously saw
693             # slicing in this piddle-less routine. But I was not using it
694             # anyway. (parser is rewritten, maybe not a problem anymore.)
695             sub generate_C_source {
696             my ($self, $fdef) = @_;
697             my $funcname = ''; # this one is returned
698             my $jacname = ''; # this one is returned
699             # Do this first now send t -> t[i], x -> x[i], p3 -> p[3]
700             # Probably a better way than doing this in a loop
701             # but overlapping matchin patterns do not work with global flag
702             # t --> t[i]
703              
704             # I tried to substitutions on $fdef vs on each line. Not much difference.
705             my $defs = {};
706             my ($lines,$def, $loopf, $noloopf, $name);
707             my (@flines) = split(/\n/, $fdef);
708             $lines = [];
709             my $prefunc = $lines;# lines before any func def
710             foreach my $oneline (@flines) { #break code into functions
711             next if $oneline =~ /^\s*end\s+(function|jacobian)\s*/;
712             if ( $oneline =~ /^\s*(function|jacobian)\s*(\w*)\s*$/ ) { # func declaration
713             $name = $2;
714             $name = "func" unless $name ne '';
715             my $type = $1;
716             $name = "jac" . $name if $type eq 'jacobian' and not $name =~ /^jac/ ;
717             $def = $defs->{$name} = {};
718             $def->{type} = $type;
719             $lines = [];
720             $def->{loop} = $lines;
721             $noloopf = 0;
722             $loopf = 0;
723             next;
724             }
725             if ( $oneline =~ /^\s*noloop/ ) { # don't want any implicit loop
726             $def->{preloop} = $lines;
727             $def->{loop} = undef;
728             $noloopf = 1;
729             next;
730             }
731             elsif ( $oneline =~ /^\s*loop/ ) { # start implicit loop
732             $def->{preloop} = $lines;
733             $lines = [];
734             $def->{loop} = $lines;
735             $loopf = 1;
736             next;
737             }
738             else {
739             push @$lines, "" .$oneline ."\n";
740             }
741             }
742              
743            
744             if ( defined $self->{TESTSYNTAX} ) {
745             my $st = '';
746             if ( @$prefunc > 0) {
747             $st .= ":PREFUNC: lines:" . scalar(@{$prefunc}). "\n";
748             $st .= join("\n",@{$prefunc}). "\n";
749             }
750             foreach my $name ( keys %$defs ) {
751             my $d = $defs->{$name};
752             $st .= "NAME: $name, TYPE: " . $d->{type};
753             if (defined $d->{preloop}) {
754             $st .= ":PRELOOP: lines:" . scalar(@{$d->{preloop}}). "\n";
755             $st .= join("\n",@{$d->{preloop}}). "\n";
756             }
757             if (defined $d->{loop}) {
758             $st .= ":LOOP: lines:" . scalar(@{$d->{loop}}). "\n";
759             $st .= join("\n",@{$d->{loop}}). "\n";
760             }
761             }
762             $self->{SYNTAXRESULTS} = $st;
763             }
764              
765             my $end_function = "\}\n\n";
766             my $end_loop = " \}\n";
767             my $start_loop = { 'jacobian' => " for(i=j=0; i
768             'function' => " for(i=0; i
769              
770             # my $dtype = $self->{TYPE};
771             my $dtype = 'FLOAT';
772             my $start_function = {
773             'jacobian' => "void JACFUNNAME($dtype *p, $dtype *d, int m, int n, $dtype *t)\n\{\n".
774             " int i,j;\n",
775             # " $dtype *t = ($dtype *) data;\n",
776             'function' => "void FITFUNNAME($dtype *p, $dtype *x, int m, int n, $dtype *t)\n\{\n".
777             " int i;\n" };
778             # " $dtype *t = ($dtype *) data;\n" };
779             my $kode =
780             "/* This file automatically created and deleted. Do not edit. */\n" .
781             "#include\n#include \n\n" .
782             join('',@$prefunc);
783              
784             my $kode1 = '';
785              
786             foreach my $name ( keys %$defs ) {
787             my $d = $defs->{$name};
788             my ($loop, $preloop, $loopcode);
789             my $type = $d->{type};
790             $funcname = $name if $type eq 'function';
791             $jacname = $name if $type eq 'jacobian';
792             if ( defined $d->{loop} ) {
793             $loopcode = join("", @{$d->{loop} });
794             if ( $loopcode =~ /^\s*$/ ) { # loop code is whitespace
795             $loopcode = undef; # so don't print it
796             }
797             else {
798             $loop = $d->{loop};
799             }
800             }
801             $preloop = $d->{preloop} if defined $d->{preloop};
802              
803             # $kode1 .= sprintf($start_function->{$type},$name);
804             $kode1 .= sprintf($start_function->{$type}, '');
805             if (defined $preloop ) {
806             foreach (@$preloop) {
807             # p5 --> p[5]
808             while ($_ =~ s/([^\w]|^)p(\d+)([^\w\[])/$1p[$2]$3/g){}
809             if ( $type eq 'function' ) {
810             # x7 -- > x[7]
811             while($_ =~ s/([^\w]|^)x(\d+)([^\w\[])/$1x[$2]$3/g){}
812             }
813             elsif ( $type eq 'jacobian' ) {
814             # d3[6] -> d[ 3+ (n-1)*6], no! [3+m*6] is correct
815             while($_ =~ /([^\w]|^)d(\d+)\[(\d+)\]/ ) {
816             my $i = "$2+m*$3" ;
817             $_ =~ s/([^\w]|^)d\d+\[\d+\]/$1d[$i]/;
818             }
819             }
820             }
821             $kode1 .= join('',@$preloop);
822             }
823             if ( defined $loop ) {
824             $kode1 .= $start_loop->{$type};
825             foreach ( @$loop ) {
826             # t -- > t[i]
827             while($_ =~ s/([^\w]|^)t([^\w\[])/$1t[i]$2/g){}
828             # p5 --> p[5]
829             while ($_ =~ s/([^\w]|^)p(\d+)([^\w\[])/$1p[$2]$3/g){}
830             if ( $type eq 'function' ) {
831             # x -> x[i]
832             while($_ =~ s/([^\w]|^)x([^\w\[])/$1x[i]$2/g){}
833             }
834             elsif ( $type eq 'jacobian' ) {
835             if ( /^\s*d\d+\[?i?\]?(.+)/ ) {
836             my $line = $1;
837             $line =~ s/\s*//; # strip space
838             $_ = " d[j++] $line\n";
839             }
840             }
841             else {
842             warn "Levmar::Func::generate_C_source: Function type neither 'function' nor 'jacobian'";
843             }
844             }
845             $kode1 .= join('',@$loop) . $end_loop;
846             }
847             $kode1 .= $end_function;
848             } #foreach my $name ..
849             my $export = $^O =~ /MSWin32/i ? '__declspec (dllexport)' : '';
850             $kode .= "
851             #define FLOAT double
852             #define JACFUNNAME $export $jacname
853             #define FITFUNNAME $export $funcname
854             " . $kode1 .
855             "
856             #undef FLOAT
857             #undef JACFUNNAME
858             #undef FITFUNNAME
859             #define FLOAT float
860             #define JACFUNNAME $export s$jacname
861             #define FITFUNNAME $export s$funcname
862             " . $kode1;
863             return ($funcname,$jacname,$kode);
864             } # end sub generate_C_source {
865              
866             # load shared library with fit function and find a symbol
867             # (pointer to fit function or jacobian in our case.)
868             # $lib_name : name of library file , eg "./func.so"
869             # $func_name : name of function, eg "square"
870             # $func_pointer : value of C level pointer to $func_name, cast to int
871             # $lib_handle : same, but for pointer to library
872             sub open_and_find {
873             my ($lib_name, $func_name) = @_;
874             my $lib_handle = 0;
875             my $func_pointer = 0;
876             my $nchar = 1000; # avoid buffer overun by sending this number to memccpy
877             my $error_message = "." x $nchar;
878             deb "call_open_and_find for lib $lib_name, func $func_name.";
879             # print STDERR "Nargs 1 ", scalar(@_) , "\n";
880             my @res = call_open_and_find($lib_name, $func_name, $lib_handle,
881             $func_pointer, $error_message , $nchar);
882             # print STDERR "Nargs 2 ", scalar(@_) , "\n";
883             # print STDERR ("call_open_and_find returned ", scalar(@res), " items\n.");
884             # print STDERR (@res),"\n";
885             return ($func_pointer, $lib_handle, $error_message);
886             # return ($func_pointer, $lib_handle, '');
887             }
888              
889             sub close_shared_object_file {
890             my ($lib_handle) = @_;
891             my $nchar = 1000; # avoid buffer overun by sending this number to memccpy
892             my $error_message = "." x $nchar;
893             my $ret = 0;
894             deb "Closing so file.";
895             # print STDERR "Nargs 3 ", scalar(@_) , "\n";
896             my @res = call_close_shared_object_file( $lib_handle, $ret, $error_message, $nchar);
897             # print STDERR "Nargs 4 ", scalar(@_) , "\n";
898             # print STDERR ("close shared returned ", scalar(@res), " items\n.");
899             # print STDERR (@res),"\n";
900             return ($ret, $error_message);
901             }
902              
903             #-----------------------------------------
904             # Some methods to call the functions
905              
906             # evaluate the function.
907             # Given parameters p and coordiante pdl t,
908             # return x(t;p) with x->dims == t->dims.
909             # The functions don't really have to have
910             # this form, but this is what we assume for
911             # this call.
912             sub call {
913             my $self = shift;
914             my ($p,$t) = @_; # pdls
915             my $x = zeroes($t);
916             if ($self->{FPOINTER} == 0) {
917             warn "Levmar::Func::call : No function loaded.";
918             return PDL->null;
919             }
920             _callf(topdl($p),$t,$x, $self->{FPOINTER});
921             return($x);
922             }
923              
924             # call jacobian and get back 2-d pdl
925             # return jac(m,n) = jacfunc(p(m),t(n))
926             sub jac_of_t {
927             my $self = shift;
928             my ($p,$t) = @_; # pdls
929             if ($self->{JPOINTER} == 0) {
930             warn "Levmar::Func::jac_of_t: No jacobian function loaded.";
931             return PDL->null;
932             }
933             my @dims = dims($t);
934             my $jac = zeroes($p->type, $p->nelem,@dims);
935             return 0 unless ref($jac) =~ /PDL/;
936             _callj($p,$t,$jac, $self->{JPOINTER});
937             return($jac);
938             }
939              
940             # treat array of derivatives as 1-d, just at the
941             # supplied c routines do. For debugging.
942             # return jac(m*n) = jacfunc(p(m),t(n))
943             sub jac_of_t1 {
944             my $self = shift;
945             my ($p,$t) = @_; # pdls
946             if ($self->{JPOINTER} == 0) {
947             warn "Levmar::Func::jac_of_t1: No jacobian function loaded.";
948             return PDL->null;
949             }
950             my @dims = dims($t);
951             foreach (@dims) { $_ *= $p->nelem}
952             my $jac = zeroes($p->type, @dims);
953             return 0 unless ref($jac) =~ /PDL/;
954             _callj1($p,$t,$jac, $self->{JPOINTER});
955             return($jac);
956             }
957             #line 958 "Func.pm"
958              
959             *_callf = \&PDL::Fit::Levmar::Func::_callf;
960              
961              
962              
963              
964             *_callj = \&PDL::Fit::Levmar::Func::_callj;
965              
966              
967              
968              
969             *_callj1 = \&PDL::Fit::Levmar::Func::_callj1;
970              
971              
972              
973              
974              
975              
976              
977             #line 158 "func.pd"
978              
979             =head1 AUTHORS
980              
981             Copyright (C) 2006 John Lapeyre.
982             All rights reserved. There is no warranty. You are allowed
983             to redistribute this software / documentation under certain
984             conditions. For details, see the file COPYING in the PDL
985             distribution. If this file is separated from the PDL distribution,
986             the copyright notice should be included in the file.
987              
988             =cut
989             #line 990 "Func.pm"
990              
991             # Exit with OK status
992              
993             1;