diff --git a/bayes_net.py b/bayes_net.py new file mode 100644 index 00000000..1273fdba --- /dev/null +++ b/bayes_net.py @@ -0,0 +1,220 @@ +import random +from difflib import SequenceMatcher + + +# Each Bayes network node is associated with a few events, +# each event can occur with its own probability +# when we learn we accumulate this probability and then +# synthesize it aftificially using ranges which ratios +# from total amount of all occurences vs occurences of +# each event. +class BayesNode: + def __init__(self, data): + self.outcomes = { } + self.total = 0.0 + self.ranges = [ ] + self.data = data + + def learn_outcome(self, node): + if node not in self.outcomes: + self.outcomes[node] = 0.0 + self.outcomes[node] += 1.0 + self.total += 1 + self._regenerate_ranges() + print("Node ", self.data, "learned outcome ", node.data, self.outcomes, self.total, "prob ", self.outcomes[node] / self.total) + print(self.outcomes, self.total) + print(self.ranges) + + def print_info(self): + print("Node ", self.data) + print("=======================================") + print("Outcomes:") + for node in self.outcomes: + print("Node", node.data, "hits", self.outcomes[node], "prob", self.outcomes[node] / self.total) + print("=======================================") + + def print_info_str(self): + s = "Node " + str(self.data) + "\n" + s += "=======================================\n" + s += "Outcomes:\n" + for node in self.outcomes: + s += "Node " + str(node.data) + " hits " + str(self.outcomes[node]) + " prob " + str(self.outcomes[node] / self.total) + "\n" + s += "=======================================\n" + return s + + def predict_outcome(self): + i = random.randint(0, self.total) + for r in self.ranges: + if i >= r[0] and i <= r[1]: + return r[2] + return None + + def _regenerate_ranges(self): + r = 0 + ranges = [ ] + + for n in self.outcomes: + ranges.append(( r, r + self.outcomes[n], n)) + r += self.outcomes[n] + self.ranges = ranges + +# If we get some state which we haven't learned yet, +# we need to do some clasification to associate it +# with something we know. +# There can be multiple ways to do that, currently +# those are using minimum string distance, if we consider +# the state as a whole +class ObjectStringAssociator: + def __init__(self): + self.objects = [ ] + def register_object(self, obj): + if obj not in self.objects: + self.objects.append(obj) + def find_closest(self, obj): + max_ratio = None + max_obj = None + if len(self.objects) == 0: + print ("No registered objects!") + for o in self.objects: + r = SequenceMatcher(None, str(o), str(obj)).ratio() + if max_ratio == None: + max_ratio = r + max_obj = o + elif max_ratio < r: + max_ratio = r + max_obj = o + return max_obj + +# for non correlated events it is better to use +# weighted approach as not all factors are equally +# valueble in informational sense. +# The factors which tend to have more different states +# have less weight than those which have less degrees +# of freedom +# i.e here we go through all the attributes we know +# checking if attribute value has been seen already, +# if it hasn't been seen the value is added to the +# attribute. +# If the attribute itself haven't been seen - it is +# added to the attributes list +# Then weight of each attribute is calculated as +# total_occurences of all attributes divided by +# number of degrees of freedom +class ObjectOrthogonalAssociator: + def __init__(self): + self.total_occurences = 0 + self.attribute_registrator = [ ] + self.objects = [ ] + def register_object(self, obj): + ind = 0 + for i in obj: + if ind >= len(self.attribute_registrator): + self.attribute_registrator.append([ ]) + if i not in self.attribute_registrator[ind]: + self.attribute_registrator[ind].append(i) + ind += 1 + if obj not in self.objects: + self.objects.append(obj) + self.total_occurences += 1 + print(self.attribute_registrator) + def _calc_weight(self, ind): + print("Attr: ", self.attribute_registrator[ind]) + weight = self.total_occurences / len(self.attribute_registrator[ind]) + return weight + def find_closest(self, obj): + max_obj = self.objects[0] + max_weight = int(0) + for o in self.objects: + w = 0.0 + for ind in range(0, min(len(o), len(obj))): + if type(o) == str: + r = SequenceMatcher(None, str(o), str(obj)).ratio() + w += self._calc_weight(ind) * r + else: + diff = float(abs(int(o[ind]) - int(obj[ind]))) + w += self._calc_weight(ind) / diff + print(o, "Weight: ", w) + if w > max_weight: + max_obj = o + max_weight = w + return max_obj + +class BayesNetwork: + def __init__(self, t): + self.hash_to_nodes = { } + self.nodes = [ ] + self.associator = t() + def learn_outcomes(self, objects): + for o in objects: + if str(o) not in self.hash_to_nodes: + print(o, " is not in ", self.hash_to_nodes, str(o)) + node = BayesNode(o) + self.hash_to_nodes[str(o)] = node + self.nodes.append(node) + self.associator.register_object(o) + nodes = [ self.hash_to_nodes[str(o)] for o in objects ] + for i in range(0, len(nodes) - 1): + nodes[i].learn_outcome(nodes[i+1]) + def predict_outcome(self, _o, steps): + objects = [ ] + print(self.hash_to_nodes) + if str(_o) not in self.hash_to_nodes: + + o = self.associator.find_closest(_o) + else: + o = _o + print("Closest is: ", o, self.hash_to_nodes, str(o)) + node = self.hash_to_nodes[str(o)] + print("Node is ", node, node.outcomes) + for i in range(0, steps): + node = node.predict_outcome() + if node == None: + return objects + objects.append(node.data) + return objects + + def print_info(self): + for node in self.nodes: + node.print_info() + + def print_info_str(self): + s = "" + for node in self.nodes: + s += node.print_info_str() + return s + +def test_orthogonal_associator(): + net = BayesNetwork(ObjectOrthogonalAssociator) + net.learn_outcomes([ "Human", "Stanislav" ]) + net.learn_outcomes([ "Human", "Jane" ]) + net.learn_outcomes([ "Human", "Slava" ]) + net.learn_outcomes([ "Dog", "Mahmud" ]) + net.learn_outcomes([ "Dog", "Marianna" ]) + net.learn_outcomes([ "Slava", "Wolfy" ]) + net.learn_outcomes([ "Dog", "Wolfy" ]) + print(net.predict_outcome("Doglava", 2)) + +def test_string_associator(): + net = BayesNetwork(ObjectStringAssociator) + net.learn_outcomes([ "Human", "Stanislav" ]) + net.learn_outcomes([ "Human", "Jane" ]) + net.learn_outcomes([ "Human", "Slava" ]) + net.learn_outcomes([ "Dog", "Mahmud" ]) + net.learn_outcomes([ "Dog", "Marianna" ]) + net.learn_outcomes([ "Slava", "Wolfy" ]) + net.learn_outcomes([ "Dog", "Wolfy" ]) + print(net.predict_outcome("Doglava", 2)) + + + +def test(): + #net = BayesNetwork(ObjectOrthogonalAssociator) + + #net.learn_outcomes([ "one", "two", "three" ]) + #net.learn_outcomes([ "four", "two", "four" ]) + test_orthogonal_associator() + test_string_associator() + #return net.predict_outcome("tone", 4) + + +test() diff --git a/page.html b/page.html new file mode 100644 index 00000000..8181c94f --- /dev/null +++ b/page.html @@ -0,0 +1,51 @@ + +
+ + + + diff --git a/process_element.py b/process_element.py new file mode 100644 index 00000000..b8b2bc5c --- /dev/null +++ b/process_element.py @@ -0,0 +1,107 @@ +import random +from difflib import SequenceMatcher + + +class ProcessNode: + def __init__(self): + self.in_node_list = [ ] + self.out_node_list = [ ] + self.state = None + def add_node(self, node, out_node = False, bidir = False, mutual = False): + if bidir: + self.in_node_list.append(node) + self.out_node_list.append(node) + else: + if out_node: + self.out_node_list.append(node) + else: + self.in_node_list.append(node) + if mutual: + node.add_node(self, out_node, False) + def remove_node(self, node, mutual = True): + if node in self.in_node_list: + i = self.in_node_list.index[node] + del self.in_node_list[i] + if node in self.out_node_list: + i = self.out_node_list.index[node] + del self.out_node_list[i] + if mutual: + node.remove_node(self, False) + + def get_state(self): + return self.state + + def process(self): + pass + + +class BooleanLogicNode(ProcessNode): + def __init__(self, bits): + ProcessNode.__init__(self) + self.state = [ 0 for i in xrange(0, bits) ] + +class LogicOne(BooleanLogicNode): + def __init__(self, bits = 1): + BooleanLogicNode.__init__(self, bits) + self.state = [ 1 for i in xrange(0, bits) ] + +class LogicZero(BooleanLogicNode): + def __init__(self, bits = 1): + BooleanLogicNode.__init__(self, bits) + +class LogicAnd(BooleanLogicNode): + def __init__(self, bits): + BooleanLogicNode.__init__(self, bits) + + def process(self): + res = all([ node.get_state() for node in self.in_node_list ]) + self.state = [ int(res) for i in xrange(0, len(self.state)) ] + +class LogicOr(BooleanLogicNode): + def __init__(self, bits): + BooleanLogicNode.__init__(self, bits) + + def process(self): + res = any([ node.get_state() for node in self.in_node_list ]) + self.state = [ int(res) for i in xrange(0, len(self.state)) ] + +class LogicNot(BooleanLogicNode): + def __init__(self, bits): + BooleanLogicNode.__init__(self, bits) + + def process(self): + self.state = [ int(not node.get_state()[0]) for node in self.in_node_list ] + + +one = LogicOne() +zero = LogicZero() + +and_el = LogicAnd(2) +or_el = LogicOr(2) +and_el.add_node(one) +and_el.add_node(one) +and_el.process() + +or_el.add_node(one) +or_el.add_node(zero) +or_el.process() + +not_el = LogicNot(2) +not_el.add_node(or_el) +not_el.add_node(and_el) +not_el.process() + +not_el2 = LogicNot(2) +not_el2.add_node(not_el) +not_el2.add_node(zero) +not_el2.process() + +print and_el.get_state() +print or_el.get_state() +print not_el.get_state() +print not_el2.get_state() + + + + + diff --git a/restart.sh b/restart.sh new file mode 100755 index 00000000..2e249c8d --- /dev/null +++ b/restart.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [ -f pid_file ] +then +pid=`cat pid_file` +kill $pid +echo "killed $pid" +fi + +python server.py 2>&1 + +pid="$!" + +echo $pid > pid_file \ No newline at end of file diff --git a/server.py b/server.py index 430d1dc7..96322a6b 100644 --- a/server.py +++ b/server.py @@ -1,19 +1,164 @@ +#!/usr/bin/python + +#import sqlite3 +import pickle + +import os +from http.server import BaseHTTPRequestHandler, HTTPServer +from bayes_net import BayesNetwork, ObjectStringAssociator +from urllib.parse import parse_qs import os import http.server import socketserver -from http import HTTPStatus +PORT_NUMBER = 8080 + +# This class will handle any incoming request from +# the browser +net = None + +conn = None +ablob = None +net_id = -1 +def create_text_field_opening_tag(_id, name): + s = '' + return s + +class myHandler(BaseHTTPRequestHandler): + + # Handler for the GET requests def do_GET(self): - self.send_response(HTTPStatus.OK) + global net_id + global net + global ablob + global conn + + self.send_response(200) + self.send_header("Content-type", "text/html") self.end_headers() - msg = 'Hello! you requested %s' % (self.path) - self.wfile.write(msg.encode()) + # Send the html message + # print self.path + s = self.path.replace("%20", " ") + # print s + s = s.replace("/", "") + s = s.replace("?", "") + # print s + s = s.replace("'", "") + # print s + s = parse_qs(s) + print(str(s)) + if "outcomes" in s: + outcomes = s["outcomes"][0].split(",") + s["outcomes"] = [i.replace(" ", "") for i in outcomes] + print(str(s)) + if "Net id" in s and "load" in s: + last_net_id = net_id + net_id = int(s["Net id"][0]) + if last_net_id != net_id: + ablob = load_blob_from_db_file("db", net_id) + if ablob != None: + print("Loaded blob") + net = load_net_from_blob(ablob) + else: + print("No blob found") + net = BayesNetwork(ObjectStringAssociator) + last_net_id = net_id + + self.wfile.write(create_text_field_opening_tag("Bayes net", "Bayes net").encode()) + self.wfile.write(net.print_info_str().encode()) + self.wfile.write(create_text_field_closing_tag().encode()) + if "submit" in s: + if net_id == -1: + net_id = int(s["Net id"][0]) + print("Learning outcomes: ", s["outcomes"]) + # self.wfile.write(str(s)) + if net == None: + net = BayesNetwork(ObjectStringAssociator) + net.learn_outcomes(s["outcomes"]) + blob = pickle.dumps(net) + if ablob != None: + remove_blob_from_file("db", net_id) + insert_blob_to_file("db", blob, net_id) + if "predict" in s and "outcomes" in s: + print("Predicting outcomes: ", s["outcomes"], s["steps"]) + o = net.predict_outcome(s["outcomes"][-1], int(s["steps"][0])) + print(o) + self.wfile.write(create_text_field_opening_tag("Results", "Results").encode()) + self.wfile.write(str(o).encode()) + self.wfile.write(create_text_field_closing_tag().encode()) + + with open("page.html", "r") as myfile: + data = myfile.read() + self.wfile.write(data.encode()) + return + + +def create_or_open_db(db_file): + db_is_new = not os.path.exists(db_file) + conn = sqlite3.connect(db_file) + if db_is_new: + print("Creating schema") + sql = """create table if not exists NETS( + ID INTEGER, + BAYES_NET BLOB)""" + conn.execute(sql) # shortcut for conn.cursor().execute(sql) + else: + print("Schema exists\n") + return conn + + +def load_blob_from_db(db_file, net_id): + conn = create_or_open_db(db_file) + cur = conn.cursor() + print(net_id) + cur.execute("select * from NETS where ID=?", (net_id,)) + blob = cur.fetchone() + cur.close() + return blob + +def load_net_from_blob(blob): + net = pickle.loads(blob[1]) + net.print_info() + return net + +def create_or_open_db_from_file(db_file): + if not os.path.exists(db_file): + f = open(str(db_file), "w") + f.close() + return None + +def load_blob_from_db_file(db_file, net_id): + create_or_open_db_from_file(str(net_id)) + myfile = open(str(net_id), "rb") + data = myfile.read() + print(data) + myfile.close() + if len(data) == 0: + print("Empty file!") + return None + return (data, data) + +def remove_blob_from_file(db_file, net_id): + os.remove(str(net_id)) + +def insert_blob_to_file(db_file, blob, net_id): + with open(str(net_id), "wb") as myfile: + myfile.write(blob) + +try: + # Create a web server and define the handler to manage the + # incoming request + server = HTTPServer(("", PORT_NUMBER), myHandler) + print("Started httpserver on port ", PORT_NUMBER) + # Wait forever for incoming htto requests + server.serve_forever() -port = int(os.getenv('PORT', 80)) -print('Listening on port %s' % (port)) -httpd = socketserver.TCPServer(('', port), Handler) -httpd.serve_forever() +except KeyboardInterrupt: + print("^C received, shutting down the web server") + server.socket.close()