From 4a217b71b7adc13abc8a3318c4c6df88dc6d2448 Mon Sep 17 00:00:00 2001 From: troyyyyy <49091847+troyyyyy@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:33:53 +0800 Subject: [PATCH] Add zoopt option --- abducer/abducer_base.py | 95 ++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/abducer/abducer_base.py b/abducer/abducer_base.py index 93810c1..ce4601b 100644 --- a/abducer/abducer_base.py +++ b/abducer/abducer_base.py @@ -16,19 +16,22 @@ sys.path.append("..") import abc from abducer.kb import add_KB, hwf_KB, add_prolog_KB import numpy as np +from zoopt import Dimension, Objective, Parameter, Opt import time class AbducerBase(abc.ABC): - def __init__(self, kb, dist_func = 'confidence', cache = True): + def __init__(self, kb, dist_func = 'confidence', zoopt = False, cache = True): self.kb = kb assert(dist_func == 'hamming' or dist_func == 'confidence') self.dist_func = dist_func self.cache = cache - + self.zoopt = zoopt + if self.cache: self.cache_min_address_num = {} self.cache_candidates = {} + def hamming_dist(self, A, B): B = np.array(B) @@ -66,38 +69,58 @@ class AbducerBase(abc.ABC): min_address_num = np.min(cost_list) idxs = np.where(cost_list == min_address_num)[0] return [candidates[idx] for idx in idxs][0] + + + + def zoopt_address_score(self, pred_res, key, address_idx): + candidates = self.kb.address_by_idx2(pred_res, key, address_idx) + return 0 if len(candidates) > 0 else 1 - def filter_all_candidates(self, pred_res, all_candidates, max_address_num, require_more_address): - if len(all_candidates) == 0: - candidates = [] - min_address_num = 0 - address_num = 0 - else: - cost_list = self.hamming_dist(pred_res, all_candidates) - min_address_num = np.min(cost_list) - address_num = min(max_address_num, min_address_num + require_more_address) - idxs = np.where(cost_list <= address_num)[0] - candidates = [all_candidates[idx] for idx in idxs] - return candidates, min_address_num, address_num + def constraint_address_num(self, solution, max_address_num): + x = solution.get_x() + return max_address_num - x.sum() + + def zoopt_get_address_idx(self, pred_res, key, max_address_num): + dimension = Dimension(size=len(pred_res), + regs=[[0, 1]] * len(pred_res), + tys=[False] * len(pred_res)) + objective = Objective(lambda sol: self.zoopt_address_score(pred_res, key, [idx for idx, i in enumerate(sol.get_x()) if i != 0]), + dim=dimension, + constraint=lambda sol: self.constraint_address_num(sol, max_address_num)) + parameter = Parameter(budget=100 * dimension.get_size(), autoset=True) + solution = Opt.min(objective, parameter).get_x() + + address_idx = [idx for idx, i in enumerate(solution) if i != 0] + address_num = solution.sum() + + return address_idx, address_num + + + def abduce(self, data, max_address_num = -1, require_more_address = 0): - pred_res, pred_res_prob, ans = data + pred_res, pred_res_prob, key = data if max_address_num == -1: max_address_num = len(pred_res) - - if self.cache and (tuple(pred_res), ans) in self.cache_min_address_num: - address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), ans)] + require_more_address) - if (tuple(pred_res), ans, address_num) in self.cache_candidates: - candidates = self.cache_candidates[(tuple(pred_res), ans, address_num)] + + if self.cache and (tuple(pred_res), key) in self.cache_min_address_num: + address_num = min(max_address_num, self.cache_min_address_num[(tuple(pred_res), key)] + require_more_address) + if (tuple(pred_res), key, address_num) in self.cache_candidates: + candidates = self.cache_candidates[(tuple(pred_res), key, address_num)] return self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) - candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, ans, max_address_num, require_more_address) - - + if self.zoopt: + address_idx, address_num = self.zoopt_get_address_idx(pred_res, key, max_address_num) + candidates = self.kb.address_by_idx(pred_res, key, address_idx) + min_address_num = address_num + else: + candidates, min_address_num, address_num = self.kb.abduce_candidates(pred_res, key, max_address_num, require_more_address) + + if self.cache: - self.cache_min_address_num[(tuple(pred_res), ans)] = min_address_num - self.cache_candidates[(tuple(pred_res), ans, address_num)] = candidates - + self.cache_min_address_num[(tuple(pred_res), key)] = min_address_num + self.cache_candidates[(tuple(pred_res), key, address_num)] = candidates + candidate = self.get_min_cost_candidate(pred_res, pred_res_prob, candidates) return candidate @@ -113,8 +136,8 @@ class AbducerBase(abc.ABC): if __name__ == '__main__': - prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0],[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] - prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0],[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob1 = [[0, 0.99, 0.01, 0, 0, 0, 0, 0, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] + prob2 = [[0, 0, 0.01, 0, 0, 0, 0, 0.99, 0, 0], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]] kb = add_KB(GKB_flag = True) abd = AbducerBase(kb, 'confidence') @@ -144,6 +167,20 @@ if __name__ == '__main__': print(res) print() + kb = add_prolog_KB() + abd = AbducerBase(kb, 'confidence', zoopt = True) + res = abd.abduce(([1, 1], prob1, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob2, 8), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 2, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 17), max_address_num = 1, require_more_address = 0) + print(res) + res = abd.abduce(([1, 1], prob1, 20), max_address_num = 2, require_more_address = 0) + print(res) + print() + kb = hwf_KB(len_list = [1, 3, 5]) abd = AbducerBase(kb, 'hamming') res = abd.abduce((['5', '+', '2'], None, 3), max_address_num = 2, require_more_address = 0) @@ -156,4 +193,4 @@ if __name__ == '__main__': print(res) print() - +