|
import random |
|
import numpy as np |
|
|
|
class Asset(): |
|
def __init__(self, cost, prob): |
|
"""Create a new state space with given dimensions.""" |
|
self.cost = cost |
|
self.prob = prob |
|
self.volume = [] |
|
print("cost: ", cost) |
|
print("prob: ", prob) |
|
print("Assume volume is bound by 0 to 100") |
|
print("Objective: max SUM [ vol_s * prob_s - cost_s ]") |
|
|
|
def hill_climb(self, maximum=None, log=False): |
|
"""Performs hill-climbing to find a solution.""" |
|
count = 0 |
|
|
|
self.volume=np.random.randint(0,100,len(self.prob)) |
|
|
|
if log: |
|
print("Initial state: profit", self.get_profit(self.volume)) |
|
|
|
|
|
while maximum is None or count < maximum: |
|
count += 1 |
|
best_neighbors = [] |
|
best_neighbor_profit = None |
|
|
|
for i,vol_s in enumerate(self.volume): |
|
|
|
for replacement in self.get_neighbors(vol_s): |
|
neighbor = self.volume.copy() |
|
neighbor[i] = replacement |
|
|
|
|
|
profit = self.get_profit(neighbor) |
|
if best_neighbor_profit is None or profit > best_neighbor_profit: |
|
best_neighbor_profit = profit |
|
best_neighbors = [neighbor] |
|
elif best_neighbor_profit == profit: |
|
best_neighbors.append(neighbor) |
|
|
|
|
|
if best_neighbor_profit <= self.get_profit(self.volume): |
|
return self.volume |
|
|
|
|
|
else: |
|
if log: |
|
print(f"Found better neighbor: cost {best_neighbor_profit}") |
|
self.volume = random.choice(best_neighbors) |
|
|
|
|
|
def random_restart(self, maximum, image_prefix=None, log=False): |
|
"""Repeats hill-climbing multiple times.""" |
|
best_volume = None |
|
best_profit = None |
|
|
|
|
|
for i in range(maximum): |
|
volume = self.hill_climb() |
|
profit = self.get_profit(volume) |
|
if best_profit is None or profit > best_profit: |
|
best_profit = profit |
|
best_volume = volume |
|
if log: |
|
print(f"{i}: Found new best state: profit {profit} with volume {volume}") |
|
else: |
|
if log: |
|
print(f"{i}: Found state: profit {profit}") |
|
|
|
return best_volume |
|
|
|
def get_profit(self, volume): |
|
profit = 0 |
|
for i,vol_s in enumerate(self.volume): |
|
profit += vol_s * self.prob[i] - self.cost[i] |
|
return profit |
|
|
|
def get_neighbors(self, vol_s): |
|
candidates = [ |
|
vol_s-5, vol_s+5 |
|
] |
|
neighbors = [] |
|
for c in candidates: |
|
if 0 <= c < 100: |
|
neighbors.append(c) |
|
return neighbors |
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
num_assets=10 |
|
s = Asset(np.random.randint(0, 10, num_assets), |
|
np.random.rand(num_assets)) |
|
|
|
s.random_restart(10, log=True) |
|
|