<filename>prac10/Autotuning/utilities/node_importance.py<gh_stars>0
#! /usr/bin/env python
"""
Autotuning System

node_importance.py

A utility which attempts to rate the importance of nodes in the variable tree.
That is, which had the greates effect on the test scores.

Usage:
./node_importance.py results.csv tune.conf
"""

# Command line arguments
from optparse import OptionParser
# Reading in csv file
from common import readCSV, readVarTree, dict2key, score_range, avg_range




def main():
    
    # Command line arguments
    usage = "\n%prog results.csv tune.conf\nWhere results.csv was generated by the auto-tuner and tune.conf is the configuration file used for the tuning."
    parser = OptionParser(usage=usage)
    
    options, args = parser.parse_args()
    
    if(len(args) != 2):
        parser.error("Expected two arguments.")
    csv_file = args[0]
    conf_file = args[1]
    
    
    
    # Import the CSV data
    print "Reading '" + csv_file + "'"
    tests, vars, possValues, repeat = readCSV(csv_file)
    
    # tests is a list of tuples (test_no, valuation, score_list, score_overall)
    
    
    
    # Get the VarTree from the conf file.
    print "Reading '" + conf_file + "'"
    vartree = readVarTree(conf_file)
    
    
    # Check the conf file and results file match.
    if vars != vartree.flatten():
        print "The variable tree in the conf file does not match the variables in the CSV file."
        exit()
    
    
    
    
    # For each node in the tree, find it's importance
    
    subtrees = get_subtrees(vartree)
    
    
    #print "%d subtrees: " % len(subtrees)
    #for st in subtrees:
    #    print st
    
    
    # For each subtree, we want to find scores in the log which were recorded 
    # while that subtree was varied. i.e. collect all scores where the other 
    # variables were constant. In general, there may be more than one setting 
    # of "other variables constant", so we'll take an avarage over these. For 
    # the system's optimisation algorithm however, there should only be one.
    
    importance = {}
    
    
    for st in subtrees:
        for t in tests:
            
            # Get the valuation of the OTHER parameters, in a canonical format.
            outsideValuation = dict(t[1]) #copies
            for v in st.flatten():
                del outsideValuation[v]
            outsideValuation = dict2key(outsideValuation)
            
            # Get the score. Use overall so some noise is reduced.
            try:
                score = float(t[3])
            except ValueError:
                continue
            
            # Add the scores
            if importance.has_key(st):
                if importance[st].has_key(outsideValuation):
                    importance[st][outsideValuation].append(score)
                else:
                    importance[st][outsideValuation] = [score]
            else:
                importance[st] = {}
                importance[st][outsideValuation] = [score]
            

    
    # Remove singletons (these are when other parameters are varying)
    for st in importance.keys():
        for val in importance[st].keys():
            if len(importance[st][val]) <= 1:
                del importance[st][val]
    
    
    
    
    # Now importance[st] is a dict mapping possible other valuations to lists 
    # of scores at that outside valuation.
    
    #print 
    #for st in subtrees:
    #    print "NODE:   " + str(st)
    #    print "SCORES: " + str(importance[st])
    #print
    
    
    # Convert the lists of scores into ranges
    # And the ranges into an average
    for st in importance.keys():
        for val in importance[st].keys():
            importance[st][val] = score_range(importance[st][val])
        importance[st] = avg_range(importance[st].values())
    
    
    
    # Print the importances sorted:
    print
    for st, imp in sorted(importance.items(), key=lambda x: x[1], reverse=True):
        print "Node:      " + str(st)
        print "Variation: %#.3g" % imp # (average range)
        print
    
    
    
    







def get_subtrees(vt):
    return [vt] + sum(map(get_subtrees, vt.subtrees), [])





if __name__ == "__main__":
    main()
    
