<reponame>LiTrans/BSMD
#!/usr/bin/env python3
import rpyc
import random
import json
from math import exp, log
from utils.iroha import set_detail_to_node, get_a_detail_written_by
from absl import flags

FLAGS = flags.FLAGS
flags.DEFINE_string('name', None, '<NAME>')
flags.DEFINE_string('private_key', None, 'Your private key to sign transactions')

# Connect to the working nodes
workers_proxies = []
# List all ports for connecting
ports = [9990, 9991, 9993, 9994]
# type the names of all workers
workers = ['worker1', 'worker2', 'worker3', 'worker4']

# Get the proxies of all workers
for port in ports:
    worker_proxy = rpyc.connect('localhost', port, config={'allow_public_attrs': True})
    workers_proxies.append(worker_proxy)


def new_state(b_car, b_cost, b_tt):
    """
    Computes a new beta using a random error. The new beta is part of the annealing process
    :param b_car: beta parameter of the car
    :param b_cost: beta parameter of the cost
    :param b_tt: beta parameter of the travel time
    :return: beta plus an error
    """
    chose_beta = random.randint(1, 3)
    error = random.uniform(-0.01, 0.01)
    new_b_car = 0
    new_b_cost = 0
    new_b_tt = 0
    if chose_beta == 1:
        new_b_car = b_car + error
        new_b_cost = b_cost
        new_b_tt = b_tt
    if chose_beta == 2:
        new_b_car = b_car
        new_b_cost = b_cost + error
        new_b_tt = b_tt
    if chose_beta == 3:
        new_b_car = b_car
        new_b_cost = b_cost
        new_b_tt = b_tt + error
    return new_b_car, new_b_cost, new_b_tt


def acceptance_probability(old_cost, new_cost, t):
    """
    Acceptance probability that the new cost improves the old cost.
    Part of the annealing process
    :param old_cost: old cost obtained from the slave nodes
    :param new_cost: new cost obtained from the slave nodes. The new cost use the parameter beta plus an error
    :param t: temperature of the annealing process
    :return: probability that the new cost improves the old cost
    """
    accept_prob = exp((new_cost - old_cost) / t)
    return accept_prob


def model(b_car, b_cost, b_tt, is_car, is_train, car_cost, car_tt, train_cost, train_tt):
    """
    This model is sent to all workers
    :param b_car:  (float) beta parameter of the car
    :param b_cost:  (float) beta parameter of the cost
    :param b_tt: (float) beta parameter of the travel time 
    :param is_car: (bool) 1 is user is traveling by car, 0 otherwise 
    :param is_train: (bool) 1 is user is traveling by train, 0 otherwise
    :param car_cost: (float)  cost fo traveling by car
    :param car_tt: (float) car travel time
    :param train_cost: (float) cost of traveling by train
    :param train_tt: (float) train travel time
    :return: 
    """
    prob_car = exp(b_car + b_cost * (car_cost - train_cost) + b_tt * (car_tt - train_tt)) / \
                  (1 + exp(b_car + b_cost * (car_cost - train_cost) + b_tt * (car_tt - train_tt)))
    observation = log(is_car * prob_car + is_train * (1 - prob_car))
    return observation


"""
Simulated annealing algorithm for solving the loglikehood choice model.
1. Use the blockchain to send the model to the worker nodes.
2. Use the blockchain to receive the cost from the worker nodes.
3. By using simulated annealing and sending-receiving information the master node solves the loglikehood choice
model without the need of personal information
:param beta_car: beta parameter of the car
:param beta_cost: beta parameter of the cost
:param beta_tt: beta parameter of the travel time
"""
beta_car = .00123
beta_cost = .00664
beta_tt = .006463
solutions = []
betas_car = []
betas_cost = []
betas_tt = []
cost = 0
cost_i = 0
x = 0
betas = str(beta_car) + ',' + str(beta_cost) + ',' + str(beta_tt)

# send parameters to workers
for worker in workers:
    # set_detail_to_node(sender, receiver, private_key, detail_key, detail_value, domain, ip):
    set_detail_to_node(FLAGS.name, worker, FLAGS.private_key, 'betas', betas, FLAGS.domain, FLAGS.ip)

# start workers
for proxy in workers_proxies:
    # this function will send the model to all workers. Also will automatically start all workers
    proxy.root.compute_cost(FLAGS.name, FLAGS.domain, FLAGS.ip, model)
all_cost = []

# get cost from all workers
for worker in workers:
    b = get_a_detail_written_by(FLAGS.name, worker, FLAGS.private_key, 'cost', FLAGS.domain, FLAGS.ip)
    result = json.loads(b)
    from_node = worker + '@' + FLAGS.domain
    c = result[from_node]['cost']
    all_cost.append(float(c))
# added cost of all workers
initial_cost = sum(all_cost)

print('initial solution = ', initial_cost)
print('initial beta_car = ', beta_car)
print('initial beta_cost = ', beta_cost)
print('initial beta_tt = ', beta_tt)
betas_car.append(beta_car)
betas_cost.append(beta_cost)
betas_tt.append(beta_tt)
solutions.append(cost)
temp = 1.0
temp_min = 0.00001
alpha = 0.9
j = 0
while temp > temp_min:
    i = 1
    while i <= 500:
        new_beta_car, new_beta_cost, new_beta_tt = new_state(beta_car, beta_cost, beta_tt)
        betas = str(new_beta_car) + ',' + str(new_beta_cost) + ',' + str(new_beta_tt)
        # send parameters to workers
        for worker in workers:
            # set_detail_to_node(sender, receiver, private_key, detail_key, detail_value, domain, ip):
            set_detail_to_node(FLAGS.name, worker, FLAGS.private_key, 'betas', betas, FLAGS.domain, FLAGS.ip)

        # get cost from all workers
        all_cost = []
        for worker in workers:
            b = get_a_detail_written_by(FLAGS.name, worker, FLAGS.private_key, 'cost', FLAGS.domain, FLAGS.ip)
            result = json.loads(b)
            from_node = worker + '@' + FLAGS.domain
            c = result[from_node]['cost']
            all_cost.append(float(c))
        # added cost of all slaves
        cost_i = sum(all_cost)

        ap = acceptance_probability(cost, cost_i, temp)
        rand = random.uniform(0, 1)
        if ap > rand:
            beta_car = new_beta_car
            beta_cost = new_beta_cost
            beta_tt = new_beta_tt
            cost = cost_i
            solutions.append(cost)
            betas_car.append(beta_car)
            betas_cost.append(beta_cost)
            betas_tt.append(beta_tt)
            print('results: ', beta_car, beta_cost, beta_tt, cost, initial_cost)
        i += 1
    temp = temp * alpha
    j += 1
print(beta_car, beta_cost, beta_tt, cost, initial_cost, solutions, betas_car, betas_cost, betas_tt)

#!/usr/bin/env python3
import rpyc
import random
import json
from math import exp, log
from utils.iroha import set_detail_to_node, get_a_detail_written_by
from absl import flags

FLAGS = flags.FLAGS
flags.DEFINE_string('name', None, '<NAME>')
flags.DEFINE_string('private_key', None, 'Your private key to sign transactions')

# Connect to the working nodes
workers_proxies = []
# List all ports for connecting
ports = [9990, 9991, 9993, 9994]
# type the names of all workers
workers = ['worker1', 'worker2', 'worker3', 'worker4']

# Get the proxies of all workers
for port in ports:
    worker_proxy = rpyc.connect('localhost', port, config={'allow_public_attrs': True})
    workers_proxies.append(worker_proxy)


def new_state(b_car, b_cost, b_tt):
    """
    Computes a new beta using a random error. The new beta is part of the annealing process
    :param b_car: beta parameter of the car
    :param b_cost: beta parameter of the cost
    :param b_tt: beta parameter of the travel time
    :return: beta plus an error
    """
    chose_beta = random.randint(1, 3)
    error = random.uniform(-0.01, 0.01)
    new_b_car = 0
    new_b_cost = 0
    new_b_tt = 0
    if chose_beta == 1:
        new_b_car = b_car + error
        new_b_cost = b_cost
        new_b_tt = b_tt
    if chose_beta == 2:
        new_b_car = b_car
        new_b_cost = b_cost + error
        new_b_tt = b_tt
    if chose_beta == 3:
        new_b_car = b_car
        new_b_cost = b_cost
        new_b_tt = b_tt + error
    return new_b_car, new_b_cost, new_b_tt


def acceptance_probability(old_cost, new_cost, t):
    """
    Acceptance probability that the new cost improves the old cost.
    Part of the annealing process
    :param old_cost: old cost obtained from the slave nodes
    :param new_cost: new cost obtained from the slave nodes. The new cost use the parameter beta plus an error
    :param t: temperature of the annealing process
    :return: probability that the new cost improves the old cost
    """
    accept_prob = exp((new_cost - old_cost) / t)
    return accept_prob


def model(b_car, b_cost, b_tt, is_car, is_train, car_cost, car_tt, train_cost, train_tt):
    """
    This model is sent to all workers
    :param b_car:  (float) beta parameter of the car
    :param b_cost:  (float) beta parameter of the cost
    :param b_tt: (float) beta parameter of the travel time 
    :param is_car: (bool) 1 is user is traveling by car, 0 otherwise 
    :param is_train: (bool) 1 is user is traveling by train, 0 otherwise
    :param car_cost: (float)  cost fo traveling by car
    :param car_tt: (float) car travel time
    :param train_cost: (float) cost of traveling by train
    :param train_tt: (float) train travel time
    :return: 
    """
    prob_car = exp(b_car + b_cost * (car_cost - train_cost) + b_tt * (car_tt - train_tt)) / \
                  (1 + exp(b_car + b_cost * (car_cost - train_cost) + b_tt * (car_tt - train_tt)))
    observation = log(is_car * prob_car + is_train * (1 - prob_car))
    return observation


"""
Simulated annealing algorithm for solving the loglikehood choice model.
1. Use the blockchain to send the model to the worker nodes.
2. Use the blockchain to receive the cost from the worker nodes.
3. By using simulated annealing and sending-receiving information the master node solves the loglikehood choice
model without the need of personal information
:param beta_car: beta parameter of the car
:param beta_cost: beta parameter of the cost
:param beta_tt: beta parameter of the travel time
"""
beta_car = .00123
beta_cost = .00664
beta_tt = .006463
solutions = []
betas_car = []
betas_cost = []
betas_tt = []
cost = 0
cost_i = 0
x = 0
betas = str(beta_car) + ',' + str(beta_cost) + ',' + str(beta_tt)

# send parameters to workers
for worker in workers:
    # set_detail_to_node(sender, receiver, private_key, detail_key, detail_value, domain, ip):
    set_detail_to_node(FLAGS.name, worker, FLAGS.private_key, 'betas', betas, FLAGS.domain, FLAGS.ip)

# start workers
for proxy in workers_proxies:
    # this function will send the model to all workers. Also will automatically start all workers
    proxy.root.compute_cost(FLAGS.name, FLAGS.domain, FLAGS.ip, model)
all_cost = []

# get cost from all workers
for worker in workers:
    b = get_a_detail_written_by(FLAGS.name, worker, FLAGS.private_key, 'cost', FLAGS.domain, FLAGS.ip)
    result = json.loads(b)
    from_node = worker + '@' + FLAGS.domain
    c = result[from_node]['cost']
    all_cost.append(float(c))
# added cost of all workers
initial_cost = sum(all_cost)

print('initial solution = ', initial_cost)
print('initial beta_car = ', beta_car)
print('initial beta_cost = ', beta_cost)
print('initial beta_tt = ', beta_tt)
betas_car.append(beta_car)
betas_cost.append(beta_cost)
betas_tt.append(beta_tt)
solutions.append(cost)
temp = 1.0
temp_min = 0.00001
alpha = 0.9
j = 0
while temp > temp_min:
    i = 1
    while i <= 500:
        new_beta_car, new_beta_cost, new_beta_tt = new_state(beta_car, beta_cost, beta_tt)
        betas = str(new_beta_car) + ',' + str(new_beta_cost) + ',' + str(new_beta_tt)
        # send parameters to workers
        for worker in workers:
            # set_detail_to_node(sender, receiver, private_key, detail_key, detail_value, domain, ip):
            set_detail_to_node(FLAGS.name, worker, FLAGS.private_key, 'betas', betas, FLAGS.domain, FLAGS.ip)

        # get cost from all workers
        all_cost = []
        for worker in workers:
            b = get_a_detail_written_by(FLAGS.name, worker, FLAGS.private_key, 'cost', FLAGS.domain, FLAGS.ip)
            result = json.loads(b)
            from_node = worker + '@' + FLAGS.domain
            c = result[from_node]['cost']
            all_cost.append(float(c))
        # added cost of all slaves
        cost_i = sum(all_cost)

        ap = acceptance_probability(cost, cost_i, temp)
        rand = random.uniform(0, 1)
        if ap > rand:
            beta_car = new_beta_car
            beta_cost = new_beta_cost
            beta_tt = new_beta_tt
            cost = cost_i
            solutions.append(cost)
            betas_car.append(beta_car)
            betas_cost.append(beta_cost)
            betas_tt.append(beta_tt)
            print('results: ', beta_car, beta_cost, beta_tt, cost, initial_cost)
        i += 1
    temp = temp * alpha
    j += 1
print(beta_car, beta_cost, beta_tt, cost, initial_cost, solutions, betas_car, betas_cost, betas_tt)
#!/usr/bin/env python3 # Connect to the working nodes # List all ports for connecting # type the names of all workers # Get the proxies of all workers Computes a new beta using a random error. The new beta is part of the annealing process     :param b_car: beta parameter of the car     :param b_cost: beta parameter of the cost     :param b_tt: beta parameter of the travel time     :return: beta plus an error Acceptance probability that the new cost improves the old cost.     Part of the annealing process     :param old_cost: old cost obtained from the slave nodes     :param new_cost: new cost obtained from the slave nodes. The new cost use the parameter beta plus an error     :param t: temperature of the annealing process     :return: probability that the new cost improves the old cost This model is sent to all workers     :param b_car:  (float) beta parameter of the car     :param b_cost:  (float) beta parameter of the cost     :param b_tt: (float) beta parameter of the travel time      :param is_car: (bool) 1 is user is traveling by car, 0 otherwise      :param is_train: (bool) 1 is user is traveling by train, 0 otherwise     :param car_cost: (float)  cost fo traveling by car     :param car_tt: (float) car travel time     :param train_cost: (float) cost of traveling by train     :param train_tt: (float) train travel time     :return: Simulated annealing algorithm for solving the loglikehood choice model. 1. Use the blockchain to send the model to the worker nodes. 2. Use the blockchain to receive the cost from the worker nodes. 3. By using simulated annealing and sending-receiving information the master node solves the loglikehood choice model without the need of personal information :param beta_car: beta parameter of the car :param beta_cost: beta parameter of the cost :param beta_tt: beta parameter of the travel time # send parameters to workers # set_detail_to_node(sender, receiver, private_key, detail_key, detail_value, domain, ip): # start workers # this function will send the model to all workers. Also will automatically start all workers # get cost from all workers # added cost of all workers # send parameters to workers # set_detail_to_node(sender, receiver, private_key, detail_key, detail_value, domain, ip): # get cost from all workers # added cost of all slaves