3 start include statements
4 # A Perl module for parsing NONMEM output files
5 use Digest
::MD5
'md5_hex';
9 use ext
::Math
::SigFigs
;
11 end include statements
13 # }}} include statements
17 # No method, just documentation
19 # The PsN output class is built to ease the (often trivial,
20 # but still time consuming) task of gathering and structuring the
21 # information contained in NONMEM output files. The major parts of a
22 # NONMEM output file are parsed and in the L</methods> section
23 # you can find a listing of the routines that are available.
33 # my $out_obj = output -> new ( filename => 'run1.lst' );
35 # my @thetas = @{$out_obj -> thetas};
36 # my @omegas = @{$out_obj -> omegas};
37 # my @ofvs = @{$out_obj -> ofvs};
47 # <a HREF="data.html">data</a>, <a HREF="model.html">model</a>
48 # <a HREF="tool/modelfit.html">tool::modelfit</a>,
49 # <a HREF="tool.html">tool</a>
55 # data, model, tool::modelfit, tool
68 # $outputObject -> new( filename => 'run1.lst' );
70 # The basic usage above creates a output object with the data
71 # in file.out parsed into memory.
73 # $outputObject -> new( filename => 'run1.lst',
76 # If I<target> is set to 'disk', the data in "run1.lst" will
77 # be left on disk in an effort to preserve memory. The file
78 # will be read if needed.
80 debug
-> warn( level
=> 2,
81 message
=> "Initiating new\tNM::output object from file $parm{'filename'}" );
82 if ( defined $this -> {'filename'} and $this -> {'filename'} ne '' ) {
83 ( $this -> {'directory'}, $this -> {'filename'} ) =
84 OSspecific
::absolute_path
( $this -> {'directory'},$this->{'filename'} );
85 if( -e
$this -> full_name
){
86 if($this -> {'target'} eq 'mem'){
87 $this -> _read_problems
;
90 debug
-> die( message
=> "The NONMEM output file ".
91 $this -> full_name
." does not exist" )
92 unless $this -> {'ignore_missing_files'};
95 debug
-> die( message
=> "No filename specified or filename equals empty string!" );
96 $this->{'filename'} = 'tempfile';
103 # {{{ register_in_database
105 start register_in_database
106 if ( $PsN::config
-> {'_'} -> {'use_database'} ) {
108 if( -e
$self -> full_name
){
110 $md5sum = md5_hex
(OSspecific
::slurp_file
($self-> full_name
));
112 # Backslashes messes up the sql syntax
113 my $file_str = $self->{'filename'};
114 my $dir_str = $self->{'directory'};
115 $file_str =~ s/\\/\//g
;
116 $dir_str =~ s/\\/\//g
;
118 my $dbh = DBI
-> connect("DBI:mysql:host=".$PsN::config
-> {'_'} -> {'database_server'}.
119 ";databse=".$PsN::config
-> {'_'} -> {'project'},
120 $PsN::config
-> {'_'} -> {'user'},
121 $PsN::config
-> {'_'} -> {'password'},
122 {'RaiseError' => 1});
128 my $sth = $dbh -> prepare
( "SELECT output_id FROM ".$PsN::config
-> {'_'} -> {'project'}.
130 "WHERE filename = '$file_str' AND ".
131 "directory = '$dir_str' AND ".
132 "md5sum = '".$md5sum."'" );
133 $sth -> execute
or debug
-> die( message
=> $sth->errstr ) ;
135 $select_arr = $sth -> fetchall_arrayref
;
138 if ( scalar @
{$select_arr} > 0 ) {
139 debug
-> warn( level
=> 1,
140 message
=> "Found an old entry in the database matching the ".
141 "current output file" );
142 if ( scalar @
{$select_arr} > 1 ) {
143 debug
-> warn( level
=> 1,
144 message
=> "Found more than one matching entry in database".
145 ", using the first" );
147 $self -> {'output_id'} = $select_arr->[0][0];
148 # Maybe we should update the table with a new model_id if such is supplied to us?
149 $self -> {'model_id'} = $select_arr->[0][1];
151 my ( $date_str, $time_str );
152 if ( $Config{osname
} eq 'MSWin32' ) {
153 $date_str = `date /T`;
154 $time_str = ' '.`time /T`;
161 my $date_time = $date_str.$time_str;
162 my @mod_str = ('','');
163 if ( defined $model_id ) {
164 @mod_str = ('model_id, ',"$model_id, ");
166 $sth = $dbh -> prepare
("INSERT INTO ".$PsN::config
-> {'_'} -> {'project'}.
169 "filename, date, directory, md5sum ) ".
170 "VALUES (".$mod_str[1].
171 "'$file_str', '$date_time', ".
172 "'$dir_str', '".$md5sum."' )");
175 $self -> {'output_id'} = $sth->{'mysql_insertid'};
176 $self -> {'model_id'} = $model_id;
180 if ( defined $self -> {'output_id'} ) {
181 foreach my $problem ( @
{$self -> {'problems'}} ) {
182 $problem -> register_in_database
( output_id
=> $self -> {'output_id'},
183 model_id
=> $model_id );
187 end register_in_database
189 # }}} register_in_database
194 $full_name = $self -> {'directory'} . $self -> {'filename'};
203 $new_output = Storable
::dclone
( $self );
208 # {{{ Definitions and help text for all accessors
211 # Since PsN output objects are read-only, once they are
212 # initialized (probably through parsing a NONMEM output file) the
213 # methods of the output class are only used to extract
214 # information, not to set any.
216 # The general structure of the values returned by the methods
217 # reflect the level where the attributes belong (problems or sub
218 # problems) and of course also the structure of the attribute
219 # itself (scalar (ofv), array (thetas) or matrix
220 # (raw_cormatrix)). Taking ofv as example, this means that the
221 # returned variable will be a (reference to a) two-dimensional
222 # array, with the indexes problem and subproblem since ofv is a
223 # scalar on the sub problem level.
225 # Most methods take two optional arguments, I<problems> and
226 # I<subproblems>. These can be used to specify which problem or sub
227 # problem that the method should extract the required information
228 # from. problems and subproblems should be references to arrays of
229 # numbers. Some methods that return information related to model
230 # parameters also take I<parameter_numbers> as another optional
231 # argument and this can be used to specify a subset of parameters.
235 # Return the standard errors for omega 1 and 3 (in all problems
238 # @seomega = @{$output_object -> seomegas( parameter_numbers => [1,3] )};
241 # comegas returns the standard deviation for elements on the
242 # diagonal and correlation coefficients for off-diagonal elements.
245 start condition_number
246 # condition_number returns the 2-norm condition number for the correlation matrix, i.e.
247 # the largest eigen value divided by the smallest.
248 # See L</comegas> for details of the method arguments.
253 start covariance_step_run
254 # Returns 1 if the covariance step was run, 0 otherwise. See
255 # L</comegas> for details.
258 end covariance_step_run
260 start covariance_step_successful
261 # Returns 1 if the covariance step was successful, 0
262 # otherwise. See L</comegas> for details on the method arguments.
265 end covariance_step_successful
267 start covariance_step_warnings
268 # Returns 0 if there were no warnings or errors printed during the
269 # covariance step, 1 otherwise. See L</comegas> for details on the
273 end covariance_step_warnings
276 # csigmas returns the standard deviation for elements on the
277 # diagonal and correlation coefficients for off-diagonal elements.
278 # See L</comegas> for details on the method arguments.
284 # cvseomegas returns the relative standard error for the omegas, i.e. SE/estimate.
285 # See L</comegas> for details on the method arguments.
291 # cvsesigmas returns the relative standard error for the sigmas, i.e. SE/estimate.
292 # See L</comegas> for details on the method arguments.
298 # cvsethetas returns the relative standard error for the thetas, i.e. SE/estimate.
299 # See L</comegas> for details on the method arguments.
305 # eigens returns the eigen values.
306 # See L</comegas> for details of the method arguments.
312 # etabar returns the ETABAR estimates.
313 # See L</comegas> for details of the method arguments.
319 # feval returns the number of function evaluations.
320 # See L</comegas> for details of the method arguments.
326 # finalparam returns the final parameter vector as it appears in the monitoring of search section.
327 # See L</comegas> for details of the method arguments.
332 start final_gradients
333 # final_gradients returns the final gradient vector as it appears in the monitoring of search section.
334 # See L</comegas> for details of the method arguments.
340 # fixedomegas returns the a vector of booleans; 1's if
341 # the parameters were fixed during the model fit, 0's
343 # See L</comegas> for details of the method arguments.
349 # fixedsigmas returns the a vector of booleans; 1's if
350 # the parameters were fixed during the model fit, 0's
352 # See L</comegas> for details of the method arguments.
358 # fixedthetas returns the a vector of booleans; 1's if
359 # the parameters were fixed during the model fit, 0's
361 # See L</comegas> for details of the method arguments.
367 # funcevalpath returns the number of function evaluations for each printed iteration in the monitoring of search section.
368 # See L</comegas> for details of the method arguments.
374 # gradient_path returns the gradients for each printed iteration in the monitoring of search section (returns a matrix for each sub problem).
375 # See L</comegas> for details of the method arguments.
381 # Returns 1 if the output object is initialized, i.e. if the I<problems>
382 # or I<filename> attributes are set. Returns 0 otherwise.
386 # initgrad returns the initial gradient vector in the monitoring of search section.
387 # See L</comegas> for details of the method arguments.
393 # initomegas returns the initial omega values.
394 # See L</comegas> for details of the method arguments.
400 # initsigmas returns the initial sigma values.
401 # See L</comegas> for details of the method arguments.
407 # initthetas returns the initial theta values.
408 # See L</comegas> for details of the method arguments.
414 # iternum returns a vector of the iteration numbers in the monitoring of search section.
415 # See L</comegas> for details of the method arguments.
421 # nind returns the number of individuals.
422 # See L</comegas> for details of the method arguments.
428 # nobs returns the number of observations.
429 # See L</comegas> for details of the method arguments.
435 # npofv returns the non-parametric objective function value.
436 # See L</comegas> for details of the method arguments.
442 # nrecs returns the number of records.
443 # See L</comegas> for details of the method arguments.
449 # npomegas returns the non-parametric omega estimates.
450 # See L</comegas> for details of the method arguments.
456 # npthetas returns the non-parametric theta estimates.
457 # See L</comegas> for details of the method arguments.
463 # nth returns the number of thetas.
464 # See L</comegas> for details of the method arguments.
470 # ofvpath returns the objective [function] values in the monitoring of search section.
471 # See L</comegas> for details of the method arguments.
477 # ofv returns the objective function value(s).
478 # See L</comegas> for details of the method arguments.
483 start omega_block_structure
484 # omega_block_structure returns the block structure for
485 # the omega parameters in a lower triangular matrix form
486 # as in the OMEGA HAS BLOCK FORM section in the NONMEM output file.
487 # See L</comegas> for details of the method arguments.
490 end omega_block_structure
493 # omeganameval returns (at the sub problem level) a hash
494 # with default parameter names , i.e. OM1, OM1_2 etc as keys
495 # and parameter estimates as values.
496 # See L</comegas> for details of the method arguments.
502 # omeganames returns the default parameter names, e.g. OM1, OM1_2, OM2, etc
503 # See L</comegas> for details of the method arguments.
509 # omegas returns the omega parameter estimates.
510 # See L</comegas> for details of the method arguments.
516 # parameter_path returns the (normalized) parameter estimates for each iteration in the monitoring of search section (Matrix returned).
517 # See L</comegas> for details of the method arguments.
523 # pval returns the P VAL (reflects the probability that the etas are not centered around zero).
524 # See L</comegas> for details of the method arguments.
530 # raw_covmatrix returns the (raw) covariance matrix including empty matrix elements marked as '.........'.
531 # See L</comegas> for details of the method arguments.
536 start raw_invcovmatrix
537 # raw_invcovmatrix returns the (raw) inverse covariance matrix including empty matrix elements marked as '.........'.
538 # See L</comegas> for details of the method arguments.
544 # raw_cormatrix returns the (raw) correlation matrix including empty matrix elements marked as '.........'.
545 # See L</comegas> for details of the method arguments.
551 # raw_omegas returns the (raw) omegas.
552 # See L</comegas> for details of the method arguments.
558 # raw_seomegas returns the (raw) omega standard error estimates.
559 # See L</comegas> for details of the method arguments.
565 # raw_sesigmas returns the (raw) sigma standard error estimates.
566 # See L</comegas> for details of the method arguments.
572 # raw_sigmas returns the (raw) sigmas.
573 # See L</comegas> for details of the method arguments.
579 # raw_tmatrix returns the (raw) T-matrix.
580 # See L</comegas> for details of the method arguments.
586 # seomegas returns the omega standard error estimates.
587 # See L</comegas> for details of the method arguments.
593 # sesigmas returns the sigma standard error estimates.
594 # See L</comegas> for details of the method arguments.
600 # sethetas returns the theta standard error estimates.
601 # See L</comegas> for details of the method arguments.
606 start significant_digits
607 # significant_digits returns the number of significant digits for the model fit.
608 # See L</comegas> for details of the method arguments.
611 end significant_digits
613 start sigma_block_structure
614 # sigma_block_structure returns the block structure for
615 # the sigma parameters in a lower triangular matrix form
616 # as in the sigma HAS BLOCK FORM section in the NONMEM output file.
617 # See L</csigmas> for details of the method arguments.
620 end sigma_block_structure
623 # sigmanameval returns (at the sub problem level) a hash
624 # with default parameter names , i.e. SI1, SI1_2 etc as keys
625 # and parameter estimates as values.
626 # See L</comegas> for details of the method arguments.
632 # sigmanames returns the default parameter names, i.e. SI1, SI1_2, SI2 etc.
633 # See L</comegas> for details of the method arguments.
639 # sigmas returns the sigma parameter estimates.
640 # See L</comegas> for details of the method arguments.
646 # simulationstep returns a boolean value 1 or 0, reflecting
647 # whether a simulation was performed or not. See L</comegas> for
648 # Details of the method arguments.
653 start minimization_successful
654 # minimization_successful returns a boolean value 1 or 0,
655 # reflecting whether the minimization was successful or not. See
656 # L</comegas> for details of the method arguments.
659 end minimization_successful
661 start minimization_message
662 # minimization_message returns the minimization message, i.e
663 # MINIMIZATION SUCCESSFUL...
664 # See L</comegas> for details of the method arguments.
667 end minimization_message
670 # thetanameval returns (at the sub problem level) a hash
671 # with default parameter names , i.e. TH1, TH2 etc as keys
672 # and parameter estimates as values.
673 # See L</comegas> for details of the method arguments.
679 # thetanames returns the default theta parameter names, TH1, TH2 etc.
680 # See L</comegas> for details of the method arguments.
686 # thetas returns the theta parameter estimates.
687 # See L</comegas> for details of the method arguments.
692 # }}} Definitions and help text for all accessors
697 # have_output returns true if the output files exits or if there
698 # is output data in memory.
699 if( -e
$self -> full_name
|| defined @
{$self -> {'problems'}}){
712 # This is a private method, and should not be used outside
715 @
{$self -> {'lstfile'}} = OSspecific
::slurp_file
($self-> full_name
) ;
716 $self -> {'lstfile_pos'} = 0;
718 # Old db code. Keep for now
719 # if ( $PsN::config -> {'_'} -> {'use_database'} and
720 # $self -> {'register_in_database'} and
721 # defined $self -> {'output_id'} ) {
722 # my $md5sum = md5_hex(@{$self -> {'lstfile'}});
723 # my $dbh = DBI -> connect("DBI:mysql:host=".$PsN::config -> {'_'} -> {'database_server'}.
724 # ";databse=".$PsN::config -> {'_'} -> {'project'},
725 # $PsN::config -> {'_'} -> {'user'},
726 # $PsN::config -> {'_'} -> {'password'},
727 # {'RaiseError' => 1});
729 # my $sth = $dbh -> prepare( "UPDATE ".$PsN::config -> {'_'} -> {'project'}.
730 # ".output SET md5sum='$md5sum' ".
731 # "WHERE output_id = ".$self -> {'output_id'});
732 # $sth -> execute or debug -> die( message => $sth->errstr ) ;
735 # $dbh -> disconnect;
740 while ( $_ = @
{$self -> {'lstfile'}}[ $self -> {'lstfile_pos'} ++ ] ) {
741 if ( /^ PROBLEM NO\.:\s+\d+\s+$/ or $self -> {'lstfile_pos'} >
742 $#{$self -> {'lstfile'}} ) {
743 if ( defined $problem_start ) {
744 my @problem_lstfile =
745 @
{$self -> {'lstfile'} } [$problem_start .. ($self ->
746 {'lstfile_pos'} - 2)];
747 $self -> add_problem
( init_data
=>
748 { lstfile
=> \
@problem_lstfile,
749 output_id
=> $self -> {'output_id'},
750 model_id
=> $self -> {'model_id'} } );
751 @problem_lstfile = undef;
754 $problem_start = $self -> {'lstfile_pos' };
757 $self -> {'lstfile'} = undef;
759 if( $self -> {'abort_on_fail'} ){
760 debug
-> die( message
=> 'The listfile "' . $self -> full_name
. '" seems malformatted.' );
762 debug
-> warn( level
=> 1,
763 message
=> 'The listfile "' . $self -> full_name
. '" seems malformatted.' );
767 $self -> {'parsed_successfully'} = 1;
769 $self -> {'parsed'} = 1;
779 # You should not really use access_any but instead the
780 # specific selector for the information you want, such as
781 # L</sigmas>, L</raw_tmatrix> or similar.
784 # TODO: Add sanity checking of parameter values (more than
785 # the automatic). e.g check that parameter_numbers is a two-
788 if ( $self -> have_output
) {
789 unless ( defined $self -> {'problems'} and
790 scalar @
{$self -> {'problems'}} > 0) {
791 $self -> _read_problems
;
794 debug
-> die( message
=> "Trying to access output object, that have no data on file(".
795 $self->full_name.") or in memory" );
797 unless( $#problems > 0 ){
798 debug
-> warn(level
=> 2,
799 message
=> "Problems undefined, using all" );
800 @problems = (1 .. scalar @
{$self -> {'problems'}});
802 my @own_problems = @
{$self -> {'problems'}};
803 foreach my $i ( @problems ) {
804 if ( defined $own_problems[$i-1] ) {
805 if ( defined( $own_problems[$i-1] -> can
( $attribute ) ) ) {
806 debug
-> warn(level
=> 2,
807 message
=> "method $attribute defined on the problem level" );
808 my $meth_ret = $own_problems[$i-1] -> $attribute;
809 if ( ref ($meth_ret) ) {
810 my @prob_attr = @
{$meth_ret};
811 if ( scalar @parameter_numbers > 0 ) {
813 foreach my $num ( @parameter_numbers ) {
814 if ( $num > 0 and $num <= scalar @prob_attr ) {
815 push( @tmp_arr, $prob_attr[$num-1] );
817 debug
-> die( message
=> "( $attribute ): no such parameter number $num!".
818 "(".scalar @prob_attr." exists)" );
821 @prob_attr = @tmp_arr;
823 push( @return_value, \
@prob_attr );
825 push( @return_value, $meth_ret ) if defined $meth_ret;
828 debug
-> warn(level
=> 2,
829 message
=> "method $attribute defined on the subproblem level" );
831 $own_problems[$i-1] ->
832 access_any
( attribute
=> $attribute,
833 subproblems
=> \
@subproblems,
834 parameter_numbers
=> \
@parameter_numbers );
835 push( @return_value, $problem_ret ) if defined $problem_ret;
838 debug
-> die( message
=> "No such problem ".($i-1) );
841 # Check the return_value to see if we have empty arrays
842 # if ( $#return_value == 0 and ref $return_value[0] and scalar @{$return_value[0]} < 1 ) {
843 # @return_value = ();
850 # {{{ high_correlations
851 start high_correlations
853 my $correlation_matrix = $self -> correlation_matrix
( problems
=> \
@problems,
854 subproblems
=> \
@subproblems );
855 my @thetanames = @
{$self -> thetanames
( problems
=> \
@problems,
856 subproblems
=> \
@subproblems )};
857 my @omeganames = @
{$self -> omeganames
( problems
=> \
@problems,
858 subproblems
=> \
@subproblems )};
859 my @sigmanames = @
{$self -> sigmanames
( problems
=> \
@problems,
860 subproblems
=> \
@subproblems )};
861 my @estimatedthetas = @
{$self -> estimatedthetas
( problems
=> \
@problems,
862 subproblems
=> \
@subproblems )};
863 my @estimatedomegas = @
{$self -> estimatedomegas
( problems
=> \
@problems,
864 subproblems
=> \
@subproblems )};
865 my @estimatedsigmas = @
{$self -> estimatedsigmas
( problems
=> \
@problems,
866 subproblems
=> \
@subproblems )};
868 #print Dumper \@omeganames;
869 #die Dumper \@estimatedomegas;
871 for ( my $i = 0; $i < scalar @
{$correlation_matrix}; $i++ ) {
872 my ( @prob_corr, @pf_corr );
873 my @names = ( @
{$thetanames[$i]}, @
{$omeganames[$i]}, @
{$sigmanames[$i]} );
874 my @estimated = ( @
{$estimatedthetas[$i]}, @
{$estimatedomegas[$i]}, @
{$estimatedsigmas[$i]} );
875 for ( my $j = 0; $j < scalar @
{$correlation_matrix -> [$i]}; $j++ ) {
876 my ( @sp_corr, @spf_corr );;
878 for ( my $row = 1; $row <= scalar @names; $row++ ) {
879 for ( my $col = 1; $col <= $row; $col++ ) {
880 if ( ( $estimated[$row-1] and $estimated[$col-1] ) ) {
881 if ( not ( $row == $col ) and
882 $correlation_matrix -> [$i][$j][$idx] > $limit or
883 $correlation_matrix -> [$i][$j][$idx] < -$limit ) {
884 push( @sp_corr, $names[$row-1]."-".$names[$col-1] );
885 push( @spf_corr, $correlation_matrix -> [$i][$j][$idx] );
892 # my @names = ( @{$thetanames[$i]}, @{$omeganames[$i]}, @{$sigmanames[$i]} );
893 # my ( @sp_corr, @spf_corr );;
894 # my ( $row, $col ) = ( 1, 1 );
895 # foreach my $element ( @{$correlation_matrix -> [$i][$j]} ) {
896 # if ( $col == $row ) {
900 # if ( $element > $limit or $element < -$limit ) {
901 # push( @sp_corr, $names[$row-1]."-".$names[$col-1] );
902 # push( @spf_corr, $element );
908 push( @prob_corr, \
@sp_corr );
909 push( @pf_corr, \
@spf_corr );
911 push( @high_correlations, \
@prob_corr );
912 push( @found_correlations, \
@pf_corr );
915 end high_correlations
916 # }}} high_correlations
918 # {{{ large_standard_errors
919 start large_standard_errors
921 foreach my $param ( 'theta', 'omega', 'sigma' ) {
922 my @names = eval( '@{$self -> '.$param.'names( problems => \@problems,'.
923 'subproblems => \@subproblems )}' );
924 my @cvs = eval( '@{$self -> cvse'.$param.'s( problems => \@problems,'.
925 'subproblems => \@subproblems )}' );
926 for ( my $i = 0; $i <= $#cvs; $i++ ) {
927 if ( $param eq 'theta' ) {
928 $large_standard_errors[$i] = [];
931 for ( my $j = 0; $j < scalar @
{$cvs[$i]}; $j++ ) {
932 if ( $param eq 'theta' ) {
933 $large_standard_errors[$i][$j] = [];
934 $found_cv[$i][$j] = [];
936 for ( my $k = 0; $k < scalar @
{$cvs[$i][$j]}; $k++ ) {
937 if ( abs($cvs[$i][$j][$k]) > eval('$'.$param.'_cv_limit') ) {
938 push( @
{$large_standard_errors[$i][$j]}, $names[$i][$k] );
939 push( @
{$found_cv[$i][$j]}, $cvs[$i][$j][$k] );
946 end large_standard_errors
947 # }}} large_standard_errors
954 my ( $number, $goal, $sigdig, $zerolim ) = @_;
955 $number = &FormatSigFigs
($number, $sigdig );
958 $test = abs($number) < $zerolim ?
1 : 0;
960 $goal = &FormatSigFigs
($goal, $sigdig );
961 $test = $number eq $goal ?
1 : 0;
966 my @thetanames = @
{$self -> thetanames
};
967 my @omeganames = @
{$self -> omeganames
};
968 my @sigmanames = @
{$self -> sigmanames
};
972 foreach my $param ( 'theta', 'omega', 'sigma' ) {
973 my @estimates = eval( '@{$self -> '.$param.'s}' );
974 my @bounds = eval( '@{$self -> '.$param.'s}' );
975 @indexes = eval( '@{$self -> '.$param.'_indexes}' ) unless ( $param eq 'theta' );
976 for ( my $i = 0; $i <= $#estimates; $i++ ) {
977 if ( $param eq 'theta' ) {
978 $near_bounds[$i] = [];
979 $found_bounds[$i] = [];
980 $found_estimates[$i] = [];
982 for ( my $j = 0; $j < scalar @
{$estimates[$i]}; $j++ ) {
983 if ( $param eq 'theta' ) {
984 $near_bounds[$i][$j] = [];
985 $found_bounds[$i][$j] = [];
986 $found_estimates[$i][$j] = [];
988 for ( my $k = 0; $k < scalar @
{$estimates[$i][$j]}; $k++ ) {
989 # Unless the parameter is fixed:
990 if ( not eval( '$self -> fixed'.$param.'s->[$i][$k]' ) ) {
991 if ( $param eq 'theta' ) {
992 if ( test_sigdig
( $estimates[$i][$j][$k],
993 $self -> lower_theta_bounds
-> [$i][$k],
994 $significant_digits, $zero_limit ) ) {
995 push( @
{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]") );
996 push( @
{$found_bounds[$i][$j]}, $self -> lower_theta_bounds
-> [$i][$k] );
997 push( @
{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
999 if ( test_sigdig
( $estimates[$i][$j][$k],
1000 $self -> upper_theta_bounds
-> [$i][$k],
1001 $significant_digits, $zero_limit ) ) {
1002 push( @
{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]") );
1003 push( @
{$found_bounds[$i][$j]}, $self -> upper_theta_bounds
-> [$i][$k] );
1004 push( @
{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
1007 my ( $upper, $lower, $sigdig );
1008 if ( $indexes[$i][$k][0] == $indexes[$i][$k][1] ) { # on diagonal
1009 ( $lower, $upper, $sigdig ) = ( 0, 1000000, $significant_digits );
1011 ( $lower, $upper, $sigdig ) = ( -1, 1, $off_diagonal_sign_digits );
1013 if ( test_sigdig
( $estimates[$i][$j][$k], $lower, $sigdig, $zero_limit ) ) {
1014 push( @
{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]" ) );
1015 push( @
{$found_bounds[$i][$j]}, $lower );
1016 push( @
{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
1018 if ( test_sigdig
( $estimates[$i][$j][$k], $upper, $sigdig, $zero_limit ) ) {
1019 push( @
{$near_bounds[$i][$j]}, eval('$'.$param."names[$i][$k]" ) );
1020 push( @
{$found_bounds[$i][$j]}, $upper );
1021 push( @
{$found_estimates[$i][$j]}, $estimates[$i][$j][$k] );
1034 # {{{ problem_structure
1035 start problem_structure
1038 unless( defined $self -> {'problems'} ) {
1039 # Try to read from disk
1040 $self -> _read_problems
;
1043 if( defined $self -> {'problems'} ) {
1044 for(my $problem = 0; $problem < @
{$self -> {'problems'}}; $problem++ ){
1045 $structure[$problem] = scalar @
{$self -> {'problems'} -> [$problem] -> {'subproblems'}};
1047 $self -> flush
if( $flush );
1050 end problem_structure
1055 # labels is this far only a wrap-around for L</thetanames>,
1056 # L</omeganames> and L</sigmanames>
1057 # The functionality of these could be moved here later on.
1059 if ( not defined $parameter_type or
1060 $parameter_type eq '' ) {
1061 my @thetanames = @
{$self -> thetanames
};
1062 my @omeganames = @
{$self -> omeganames
};
1063 my @sigmanames = @
{$self -> sigmanames
};
1064 for ( my $i = 0; $i <= $#thetanames; $i++ ) {
1065 if( defined $thetanames[$i] ){
1066 push( @
{$labels[$i]}, @
{$thetanames[$i]} );
1068 if( defined $omeganames[$i] ){
1069 push( @
{$labels[$i]}, @
{$omeganames[$i]} );
1071 if( defined $sigmanames[$i] ){
1072 push( @
{$labels[$i]}, @
{$sigmanames[$i]} );
1076 my $accessor = $parameter_type.'names';
1077 @labels = @
{$self -> $accessor};
1086 # flush is not an accessor method. As its name implies it flushes the
1087 # output objects memory by setting the I<problems> attribute to undef.
1088 # This method can be useful when many output objects are handled and
1089 # the memory is limited.
1091 # Flushes the object to save memory. There is no need to
1092 # synchronize the ouptut object before this since they are read-
1096 $self -> {'problems'} = undef;
1097 $self -> {'synced'} = 0;