Sample program regression_test, in three languages

The tri-language program required few changes from its bi-lingual counterpart in the previous chapter. In fact, none of the Haskell interface files were changed, so they are not duplicated here. The only changes were a routine to shuffle values from Python lists into Eiffel arrays of doubles, and of course the Python script to load the values from disk. Values were provided in the following format:

Example 14-1. Data file for regression_test

130,186
650, 699
99, 132
 150, 272
128, 291
302, 331
95, 199
945, 1890
368, 788
961, 1601

These values were loaded and parsed by the Python function paired_arrays_from_file, located in the loader.py module:

Example 14-2. The loader.py module

#simple module to load numbers from a file

import re

def paired_arrays_from_file( filename ) :
    a_series = []
    b_series = []
    f = open(filename, "r" )
    lines = f.readlines()
    regex = re.compile( r"^\s*(\S*?),\s*(\S*?)\s*$" )
    for line in lines :
        matches = regex.match( line )
        if len( matches.group( 1 ) ) > 0 and len( matches.group( 2 ) ) > 0 :
            a_series.append( float( matches.group( 1 ) ) )
            b_series.append( float( matches.group( 2 ) ) )
    return( a_series, b_series );

The loader.py module and Haskell code were controlled by the overall application regression_test.e:

Example 14-3. The regression_test.e source file

class REGRESSION_TEST
inherit
   REGRESSION_WRAPPER
   PYTHON_CLIENT
   
creation
   make
   
feature
   
   array_from_python_list( pyobj : PYTHON_OBJECT ) : ARRAY[ DOUBLE ] is
      local
	 i : INTEGER
	 n : PYTHON_FLOAT
	 pyarr : PYTHON_LIST
      do
	 create pyarr.make_from_python_object( pyobj )
	 create Result.with_capacity( pyarr.length, 0 )
	 from i := pyarr.lower until i > pyarr.upper loop
	    create n.make_from_python_object( pyarr.item( i ) )
	    Result.add_last( n.to_double )
	    i := i + 1
	 end
      end
   
   show_regression( filename : STRING ) is
      local
	 series_a, series_b : ARRAY[ DOUBLE ]
	 m : LOADER
	 t : PYTHON_TUPLE
	 r : INTEGER
      do
	 py_initialize
	 r := py_run_simple_string( "import sys" );
	 r := py_run_simple_string( "sys.path.append( '.' )" )
	 start_haskell
	 create m.make
	 create t.make_from_python_object( m.paired_arrays_from_file( << filename >> ) )
	 series_a := array_from_python_list( t.item( 0 ) )
	 series_b := array_from_python_list( t.item( 1 ) )
	 io.put_string( "%N%NLinear regression of series: Beta-0: " )
	 io.put_double( beta_0( series_a, series_a.count, series_b, series_b.count ) )
	 io.put_string( " Beta-1: " )
	 io.put_double( beta_1( series_a, series_a.count, series_b, series_b.count ) )
	 io.put_new_line
      end
   
   make is
      do
	 if argument_count /= 1 then
	    io.put_string( "Usage : regression_test filename%N%N" )
	 else
	    show_regression( argument( 1 ) )
	 end
      rescue
	 if not py_err_occurred.is_null then
	    py_err_print
	 end
      end
   
end
   

The resultant output is the same as the earlier example program, which indicates that we have done our job correctly:

Example 14-4. Output from the poly_regression version of regression_test

[vputz@yak_prime poly_regression]$ ./regression_test test_1

Linear regression of series: Beta-0: -22.552533 Beta-1: 1.727932

At last, we have realized the vision of multilingual programming using Eiffel, Haskell, and Python together in the same executable.