#########################################################
##  CS 2500 (Fall 2009), Assignment #7 (mod)           ##
##   Script File Name: stats5.py                       ##
##       Student Name: Todd Wareham                    ##
##         Login Name: harold                          ##
##              MUN #: 8008765                         ##
#########################################################
"""
Given the name of a textfile of commands (one per line), for a 
 1D real-number vector statistics derivation and display system, execute 
 these commands and print results or error messages to standard 
 output as appropriate.
 
For a full description of this system, please see the on-line description of
 Assignment #7.

This script is a variant of stats4.py (answer to Assignment #7) which places
 the interpretation-loop from the main program in a function interpret(). 
 This is done to allow profiling of the runtimes of the various functions in
 this script via script profile_stats5.py.
"""

import sys
import math


def initVector():
    return {}


def readVector(vecFName):
    f = open(vecFName, "r")
    line = f.read()
    f.close()
    return [float(x) for x in line.split()]
    

def extractVector(vecType, vecNum, matFName):

    M = []
    for line in file(matFName):
        M.append([float(x) for x in line.split()])

    V = []
    if vecType == "row":
        V = M[vecNum - 1]
    elif vecType == "col":
        for i in range(0, len(M)):
            V.append(M[i][vecNum - 1])
    elif vecType == "dia":
        x = y = 0
	if (vecNum >= 0):
	    y = y + vecNum
        else:
	    x = x -vecNum
        while (x < len(M)) and (y < len(M[0])):
	    V.append(M[x][y])
	    x = x + 1
	    y = y + 1
        
    return V


def listVector(vecDict):
    if len(vecDict) == 0:
        return ""
    else:
        return "\n".join(sorted(vecDict))


def setVector(vecName, vecList, vecDesc, vecDict):
    vecDict[vecName] = (vecList, vecDesc)
    return


def isVector(vecName, vecDict):
    return vecName in vecDict


def getVector(vecName, vecDict):
    if vecName not in vecDict:
        return "error: vector " + vecName + " not stored"
    else:
        return vecDict[vecName]


def vectorStats(vecName, vecDict):

    if vecName not in vecDict:

        return "error: vector " + vecName + " not stored"

    else:

        V = vecDict[vecName][0]

        mean = sum(V)/len(V)

	var = 0.0
        for i in range(0, len(V)):
            var = var + (V[i] - mean)**2
        var = var/len(V)

        stdDev = math.sqrt(var)

        return (len(V), sum(V), mean, min(V), max(V), stdDev, var)

 
def vectorCorr(vecName1, vecName2, vecDict):

    if vecName1 not in vecDict:

        return "error: vector " + vecName1 + " not stored"

    elif vecName2 not in vecDict:

        return "error: vector " + vecName2 + " not stored"

    elif (len(getVector(vecName1, vecDict)[0]) != \
         len(getVector(vecName2, vecDict)[0])):

        return "error: specified vectors have different lengths"

    else:

        V1 = getVector(vecName1, vecDict)[0]
        V2 = getVector(vecName2, vecDict)[0]

        sumV1 = sumV2 = sumV1V2 = sumV1Sq = sumV2Sq = 0.0

        for i1 in range(0, len(V1)):
            sumV1 = sumV1 + V1[i1]
            sumV2 = sumV2 + V2[i1]
            sumV1V2 = sumV1V2 + (V1[i1] * V2[i1])
	    sumV1Sq = sumV1Sq + V1[i1]**2
	    sumV2Sq = sumV2Sq + V2[i1]**2

        if math.sqrt((sumV1Sq - ((sumV1**2)/len(V1))) * \
	                         (sumV2Sq - ((sumV2**2)/len(V1)))) == 0.0:
	    return 0.0
        else:
             return (sumV1V2 - ((sumV1 * sumV2)/len(V1))) / \
	             math.sqrt((sumV1Sq - ((sumV1**2)/len(V1))) * \
	                       (sumV2Sq - ((sumV2**2)/len(V1))))


def clearVector(vecDict):
    vecDict.clear()
    return


def interpret(commandfile):

    vecDict = initVector()

    for line in file(commandfile):

        print ">>> " + line.rstrip()

        command = line.split()

        if ((len(command) == 4) and (command[0] == "read") and (command[2] == "into")):

            setVector(command[3], readVector(command[1]), command[1], vecDict)

        elif ((len(command) == 7) and (command[0] == "read") and 
                                      (command[1] in ["row", "col", "dia"]) and
                                      (command[3] == "from") and
                                      (command[5] == "into")):

            setVector(command[6], extractVector(command[1], int(command[2]), command[4]), 
                                  command[1] + " " + command[2] + " of " + command[4], vecDict)

        elif ((len(command) == 1) and (command[0] == "list")):

            if listVector(vecDict):
                print listVector(vecDict)

        elif (len(command) == 2):

             subcommand = ["length", "sum", "mean", "min", "max", "stdDev", "var"]

             if (command[0] == "print"):

	         if not isVector(command[1], vecDict):
	             print "error: vector " + command[1] + " not stored"
                 else:
                     print str(getVector(command[1], vecDict)[0]) + \
		           "\n (" + getVector(command[1], vecDict)[1] + ")"

             elif (command[0] in subcommand):

	         if not isVector(command[1], vecDict):
	             print "error: vector " + command[1] + " not stored"
                 else:
                     print vectorStats(command[1], vecDict)[subcommand.index(command[0])]

             else:

                 print "error: invalid command"

        elif ((len(command) == 3) and (command[0] == "corr")):

            print vectorCorr(command[1], command[2], vecDict)

        elif ((len(command) == 1) and (command[0] == "clear")):

            clearVector(vecDict)

        elif ((len(command) == 1) and (command[0] == "exit")):

            break

        else:

            print "error: invalid command"

    return


if __name__ == "__main__":

    if len(sys.argv) != 2:
        print "usage: ", sys.argv[0], " commandfile"
        sys.exit(1)

    interpret(sys.argv[1])

