Sample program regression_test

Because of the additional necessary hand-edited files, the regression_test application has more source code than our other sample applications:

Example 13-9. Source code for the regression_test sample program

First, the Regression.hs file, containing the Haskell functions to be exported:

module Regression where

import Int

average		:: [Double] -> Double
average []		= 0
average x		= sum x / fromInt(length x)

square 	:: Num a => a -> a
square x	= x^2

dcount :: [Double] -> Double
dcount xs = fromInt( length xs )

mult_terms	:: [Double] -> [Double] -> [Double]
mult_terms [] []		= []
mult_terms (x:xs) (y:ys)	= [x*y] ++ mult_terms xs ys

beta_1 :: [Double] -> [Double] -> Double
beta_1 xs ys = top / bottom
	 where
           top = sum( mult_terms xs ys ) - dcount xs * average xs * average ys
	   bottom = sum ( map square xs) - dcount xs * square ( average xs )

beta_0 :: [Double] -> [Double] -> Double
beta_0 xs ys = average ys - beta_1 xs ys * average xs

...and the IDL file for exporting those functions, Regression_proxy.idl

module Regression {
  [pure]double beta_0( [in, size_is(len_xs)]double* xs, [in]int len_xs, [in, size_is(len_ys)]double* ys, [in]int len_ys );
  [pure]double beta_1( [in, size_is(len_xs)]double* xs, [in]int len_xs, [in, size_is(len_ys)]double* ys, [in]int len_ys );
}

The interface file for SWIG, Regression.i...

%module regression
%{
#include "Regression.h"
%}

double  beta_0 ( /*[in, size_is(len_xs)]*/double* xs
               , /*[in]*/int len_xs
               , /*[in, size_is(len_ys)]*/double* ys
               , /*[in]*/int len_ys );
/*[pure]*/
double  beta_1 ( /*[in, size_is(len_xs)]*/double* xs
               , /*[in]*/int len_xs
               , /*[in, size_is(len_ys)]*/double* ys
               , /*[in]*/int len_ys );

extern void startupHaskell( int argc, char argv[][] );
extern void start_haskell( void );


...and the wrapper function to start the Haskell runtime, wrap_start_haskell.c:

extern void startupHaskell( int argc, char**argv );

void start_haskell( void )
{
	char * argv[] = { "bob", "tim" };
	startupHaskell( 1, argv );
}

Finally, the actual Eiffel test program:

class REGRESSION_TEST
inherit
   REGRESSION_WRAPPER
   
creation
   make
   
feature
   
   eol : ARRAY[DOUBLE] is  
      once
	 create Result.from_collection( << 130.0, 650.0, 99.0, 150.0, 128.0, 302.0, 95.0, 945.0, 368.0, 961.0 >> )
      end
   
   enc : ARRAY[DOUBLE] is 
      once
	 create Result.from_collection( << 163.0, 765.0, 141.0, 166.0, 137.0, 355.0, 136.0, 1206.0, 433.0, 1130.0 >> )
      end
   
   anc : ARRAY[DOUBLE] is 
      once
	 create Result.from_collection( << 186.0, 699.0, 132.0, 272.0, 291.0, 331.0, 199.0, 1890.0, 788.0, 1601.0 >> )
      end
   
   make is
      local
      do
	 start_haskell
	 io.put_string( "%N%NEst obj vs actual new/changed: Beta-0: " )
	 io.put_double( beta_0( eol, eol.count, anc, anc.count ) )
	 io.put_string( " Beta-1: " )
	 io.put_double( beta_1( eol, eol.count, anc, anc.count ) )
	 io.put_new_line
	 io.put_string( "Est new/changed vs actual new/changed: Beta-0: " )
	 io.put_double( beta_0( enc, enc.count, anc, anc.count ) )
	 io.put_string( " Beta-1: " )
	 io.put_double( beta_1( enc, enc.count, anc, anc.count ) )
	 io.put_new_line
      end
   
end
   

The program runs, simulating one of the runs of PSP program 4a, with static values for the arrays of numbers rather than reading them from a file. It produces the output shown below:

Example 13-10. Output from the regression_test application

[vputz@yak_prime regression]$ ./regression_test 

Est obj vs actual new/changed: Beta-0: -22.552533 Beta-1: 1.727932
Est new/changed vs actual new/changed: Beta-0: -23.923888 Beta-1: 1.430967
[vputz@yak_prime regression]$ 

The final program is rather huge--1.4 megabytes before stripping and 590k after, but it does work, and works rather well. With this toy example, we haven't done much to convince anyone that multilanguage programming will save program space or run-time, but the reduction in code size of the simple regression calculation should indicate that the volume of source code generated for a large, complex computing application could be significantly reduced, gaining simplicity and ease-of-understanding from the use of a functional language as the computational core. All that remains to make our multilanguage experiment complete is the successful merging of all three languages into a single program...