kevin-toolbox-dev 1.1.1__py3-none-any.whl → 1.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kevin_toolbox/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.1.1"
1
+ __version__ = "1.1.3"
2
2
 
3
3
 
4
4
  import os
@@ -12,5 +12,5 @@ os.system(
12
12
  os.system(
13
13
  f'python {os.path.split(__file__)[0]}/env_info/check_validity_and_uninstall.py '
14
14
  f'--package_name kevin-toolbox-dev '
15
- f'--expiration_timestamp 1702873414 --verbose 0'
15
+ f'--expiration_timestamp 1703667553 --verbose 0'
16
16
  )
@@ -16,7 +16,8 @@ def copy_(var, b_deepcopy=False):
16
16
  return copy.deepcopy(var)
17
17
 
18
18
  return traverse(var=[var], match_cond=lambda _, __, value: isinstance(value, (list, dict,)),
19
- action_mode="replace", converter=lambda _, value: value.copy(), b_traverse_matched_element=True)[0]
19
+ action_mode="replace", converter=lambda _, value: value.copy(),
20
+ traversal_mode="dfs_pre_order", b_traverse_matched_element=True)[0]
20
21
 
21
22
 
22
23
  if __name__ == '__main__':
@@ -1,7 +1,7 @@
1
1
  from kevin_toolbox.computer_science.algorithm.for_nested_dict_list.name_handler import parse_name
2
2
 
3
3
 
4
- def get_value_by_name(var, name):
4
+ def get_value_by_name(var, name, b_pop=False, **kwargs):
5
5
  """
6
6
  通过解释名字得到取值方式,然后到 var 中获取对应部分的值。
7
7
 
@@ -13,18 +13,36 @@ def get_value_by_name(var, name):
13
13
  ":acc@1" 或者 "|acc|1" 等。
14
14
  注意,在 name 的开头也可以添加任意非解释方式的字符,本函数将直接忽略它们,比如下面的:
15
15
  "var:acc@1" 和 "xxxx|acc|1" 也能正常读取。
16
+ b_pop: <boolean> 是否将值从 var 中移除
17
+ 默认为 False
18
+ default: 默认值
19
+ - 不设置(默认)。当取值失败时将报错。
20
+ - 设置为任意值。取值失败时将返回该值。
16
21
  """
17
22
  _, method_ls, node_ls = parse_name(name=name, b_de_escape_node=True)
18
23
 
19
- for method, node in zip(method_ls, node_ls):
20
- if method == "@":
21
- var = var[eval(node)]
22
- elif method == "|":
23
- try:
24
- var = var[node]
25
- except:
26
- var = var[eval(node)]
27
- else: # ":"
28
- var = var[node]
24
+ try:
25
+ pre, cur = None, var
26
+ node = None
27
+ for method, node in zip(method_ls, node_ls):
28
+ pre, cur = cur, None
29
+ if method == "@":
30
+ node = eval(node)
31
+ elif method == "|":
32
+ try:
33
+ _ = pre[node]
34
+ except:
35
+ node = eval(node)
36
+ cur = pre[node]
29
37
 
30
- return var
38
+ if b_pop and len(node_ls) > 0:
39
+ assert isinstance(pre, (dict, list,)), \
40
+ f'pop is only supported when the parent node type is list or dict, but got a {type(pre)}'
41
+ pre.pop(node)
42
+ except:
43
+ if "default" in kwargs:
44
+ cur = kwargs["default"]
45
+ else:
46
+ raise IndexError(f'invalid name {name}')
47
+
48
+ return cur
@@ -16,7 +16,7 @@ def set_value_by_name(var, name, value, b_force=False):
16
16
  "var:acc@1" 和 "xxxx|acc|1" 也能正常写入。
17
17
  value: 待赋给的值
18
18
  b_force: <boolean> 当无法设置时,是否尝试创建或者修改节点
19
- 默认为 False
19
+ 默认为 False,此时若无法设置,则报错
20
20
  当设置为 True,可能会对 var 的结构产生不可逆的改变,请谨慎使用。
21
21
  - 根据取值方式的不同,新创建或者修改的节点的类型可能是 dict 或者 list,
22
22
  对于 list,其中缺省值填充 None。
@@ -1,8 +1,21 @@
1
+ from enum import Enum
1
2
  from kevin_toolbox.computer_science.algorithm.for_nested_dict_list.name_handler import escape_node
2
3
 
3
4
 
5
+ class ACTION_MODE(Enum):
6
+ remove = 1
7
+ replace = 2
8
+ skip = 3
9
+
10
+
11
+ class TRAVERSAL_MODE(Enum):
12
+ dfs_pre_order = 1
13
+ dfs_post_order = 2
14
+ bfs = 3
15
+
16
+
4
17
  def traverse(var, match_cond, action_mode="remove", converter=None,
5
- b_use_name_as_idx=False, b_traverse_matched_element=False):
18
+ b_use_name_as_idx=False, traversal_mode="dfs_pre_order", b_traverse_matched_element=False):
6
19
  """
7
20
  遍历 var 找到符合 match_cond 的元素,将其按照 action_mode 指定的操作进行处理
8
21
 
@@ -27,43 +40,109 @@ def traverse(var, match_cond, action_mode="remove", converter=None,
27
40
  converter: <func> 参见 action_mode 中的 "replace" 模式
28
41
  函数类型为 def(idx, value): ...
29
42
  其中 idx 和 value 的含义参见参数 match_cond 介绍
43
+ traversal_mode: <str> 遍历的模式、顺序
44
+ 目前支持:
45
+ "dfs_pre_order" 深度优先、先序遍历
46
+ "dfs_post_order" 深度优先、后序遍历
47
+ "bfs" 宽度优先
48
+ 默认为 "dfs_pre_order"
30
49
  b_use_name_as_idx: <boolean> 对于 match_cond/converter 中的 idx 参数,是传入整体的 name 还是父节点的 index 或 key。
31
50
  默认为 False
32
51
  b_traverse_matched_element <boolean> 对于匹配上的元素,经过处理后,是否继续遍历该元素的内容
33
52
  默认为 False
34
53
  """
35
54
  assert callable(match_cond)
36
- assert action_mode in {"replace", "remove", "skip"}
37
- if action_mode == "replace":
55
+ assert action_mode in ACTION_MODE.__members__.keys()
56
+ action_mode = ACTION_MODE.__members__[action_mode]
57
+ if action_mode is ACTION_MODE.replace:
38
58
  assert callable(converter)
59
+ #
60
+ assert traversal_mode in TRAVERSAL_MODE.__members__.keys()
61
+ traversal_mode = TRAVERSAL_MODE.__members__[traversal_mode]
39
62
 
40
- return recursive_(var, match_cond, action_mode, converter, b_use_name_as_idx, b_traverse_matched_element, "")
63
+ if traversal_mode is TRAVERSAL_MODE.bfs:
64
+ return _bfs(var, match_cond, action_mode, converter, b_use_name_as_idx, b_traverse_matched_element)
65
+ else:
66
+ return _dfs(var, match_cond, action_mode, converter, b_use_name_as_idx, traversal_mode,
67
+ b_traverse_matched_element, "")
68
+
69
+
70
+ def _bfs(var, match_cond, action_mode, converter, b_use_name_as_idx, b_traverse_matched_element):
71
+ temp = [("", var)]
41
72
 
73
+ while len(temp):
74
+ pre_name, i = temp.pop(0)
75
+ if isinstance(i, (list, dict)):
76
+ keys = list(range(len(i)) if isinstance(i, list) else i.keys())
77
+ keys.reverse() # 反过来便于 列表 弹出元素
78
+ idx_ls = _gen_idx(i, keys, b_use_name_as_idx, pre_name)
42
79
 
43
- def recursive_(var, match_cond, action_mode, converter, b_use_name_as_idx, b_traverse_matched_element, pre_name):
80
+ # 匹配&处理
81
+ for k, idx in zip(keys, idx_ls):
82
+ b_matched, b_popped = _deal(i, k, idx, match_cond, converter, action_mode)
83
+ if b_popped or (b_matched and not b_traverse_matched_element):
84
+ continue
85
+ # 添加到队尾
86
+ temp.append((idx, i[k]))
87
+
88
+ return var
89
+
90
+
91
+ def _dfs(var, match_cond, action_mode, converter,
92
+ b_use_name_as_idx, traversal_mode, b_traverse_matched_element, pre_name):
44
93
  if isinstance(var, (list, dict)):
45
- items = reversed(list(enumerate(var))) if isinstance(var, list) else list(var.items())
46
- for k, v in items:
47
- if b_use_name_as_idx:
48
- method = "@" if isinstance(var, list) else ":"
49
- idx = f'{pre_name}{method}{escape_node(node=k, b_reversed=False, times=1)}'
50
- else:
51
- idx = k
52
- # 匹配
53
- b_matched = match_cond(type(var), idx, v)
54
- # 处理
55
- if b_matched:
56
- if action_mode == "remove":
57
- var.pop(k)
58
- elif action_mode == "replace":
59
- var[k] = converter(idx, v)
60
- else:
61
- pass
94
+ keys = list(range(len(var)) if isinstance(var, list) else var.keys())
95
+ keys.reverse() # 反过来便于 列表 弹出元素
96
+ idx_ls = _gen_idx(var, keys, b_use_name_as_idx, pre_name)
97
+
98
+ #
99
+ if traversal_mode is TRAVERSAL_MODE.dfs_pre_order:
100
+ # 先序
101
+ # 匹配&处理
102
+ deal_res_ls = []
103
+ for k, idx in zip(keys, idx_ls):
104
+ deal_res_ls.append(_deal(var, k, idx, match_cond, converter, action_mode))
62
105
  # 递归遍历
63
- if b_matched and not b_traverse_matched_element:
64
- continue
65
- var[k] = recursive_(var[k], match_cond, action_mode, converter, b_use_name_as_idx,
66
- b_traverse_matched_element, idx)
106
+ for (b_matched, b_popped), k, idx in zip(deal_res_ls, keys, idx_ls):
107
+ if b_popped or (b_matched and not b_traverse_matched_element):
108
+ continue
109
+ var[k] = _dfs(var[k], match_cond, action_mode, converter, b_use_name_as_idx, traversal_mode,
110
+ b_traverse_matched_element, idx)
111
+ else:
112
+ # 后序
113
+ # 递归遍历
114
+ for k, idx in zip(keys, idx_ls):
115
+ var[k] = _dfs(var[k], match_cond, action_mode, converter, b_use_name_as_idx, traversal_mode,
116
+ b_traverse_matched_element, idx)
117
+ # 匹配&处理
118
+ for k, idx in zip(keys, idx_ls):
119
+ _deal(var, k, idx, match_cond, converter, action_mode)
67
120
  else:
68
121
  pass
69
122
  return var
123
+
124
+
125
+ def _deal(var, k, idx, match_cond, converter, action_mode):
126
+ """处理节点"""
127
+ # 匹配
128
+ b_matched = match_cond(type(var), idx, var[k])
129
+ b_popped = False
130
+ # 处理
131
+ if b_matched:
132
+ if action_mode is ACTION_MODE.remove:
133
+ var.pop(k)
134
+ b_popped = True
135
+ elif action_mode is ACTION_MODE.replace:
136
+ var[k] = converter(idx, var[k])
137
+ else:
138
+ pass
139
+ return b_matched, b_popped
140
+
141
+
142
+ def _gen_idx(var, keys, b_use_name_as_idx, pre_name):
143
+ if b_use_name_as_idx:
144
+ method = "@" if isinstance(var, list) else ":"
145
+ idx_ls = [f'{pre_name}{method}{escape_node(node=k, b_reversed=False, times=1)}' for k in keys]
146
+ else:
147
+ idx_ls = keys
148
+ return idx_ls
@@ -9,8 +9,12 @@ def eval_references(var, node_s, order, converter_for_ref=None, converter_for_re
9
9
  var:
10
10
  node_s: <dict> 引用节点,parse_references() 返回的结果
11
11
  order: <list of name> 计算顺序,cal_relation_between_references() 返回的结果
12
- converter_for_ref: <callable> 对引用值施加何种处理
13
- 形如 def(idx, v): ... 的函数,其中 idx 是被引用节点的名字,v是其值
12
+ converter_for_ref: <callable> 对被引用节点施加何种处理
13
+ 形如 def(idx, v): ... 的函数,其中 idx 是被引用节点的名字,v是其值,
14
+ 返回的结果将替换掉被引用节点中原来的值。
15
+ 注意:
16
+ - 处理后得到的结果将替换掉原引用节点的值。(重要所以说两次)
17
+ - 当同一节点被多次引用时,仅会被处理、替换一次。
14
18
  converter_for_res: <callable> 对计算结果施加何种处理
15
19
  形如 def(idx, v): ... 的函数,其中 idx 是节点的名字,v是计算结果
16
20
  """
@@ -18,13 +22,18 @@ def eval_references(var, node_s, order, converter_for_ref=None, converter_for_re
18
22
  assert converter_for_ref is None or callable(converter_for_ref)
19
23
  assert converter_for_res is None or callable(converter_for_res)
20
24
 
25
+ processed_ref_nodes = set()
26
+
21
27
  for name in order:
22
28
  details = node_s[name]
23
29
  # 获取依赖值
24
- for k, v in details["paras"].items():
25
- v_new = get_value_by_name(var=var, name=v)
26
- if converter_for_ref is not None:
27
- v_new = converter_for_ref(v, v_new)
30
+ for k, idx in details["paras"].items():
31
+ v_new = get_value_by_name(var=var, name=idx)
32
+ if converter_for_ref is not None and idx not in processed_ref_nodes:
33
+ v_new = converter_for_ref(idx, v_new)
34
+ # 赋值
35
+ set_value_by_name(var=var, name=idx, value=v_new, b_force=False)
36
+ processed_ref_nodes.add(idx)
28
37
  details["paras"][k] = v_new
29
38
  # 计算
30
39
  res = eval(details["expression"], details["paras"])
@@ -57,7 +57,12 @@ class Registry:
57
57
  __new__函数返回的实例,将作为self参数被传入到__init__函数。
58
58
  如果__new__函数返回一个已经存在的实例(不论是哪个类的),__init__还是会被调用的,所以要特别注意__init__中对变量的赋值。
59
59
  """
60
- uid = kwargs.get("uid", cls.__counter)
60
+ if "uid" in kwargs:
61
+ uid = kwargs["uid"]
62
+ else:
63
+ while cls.__counter in cls.__instances:
64
+ cls.__counter += 1
65
+ uid = cls.__counter
61
66
 
62
67
  # 获取实例
63
68
  if uid in cls.__instances:
@@ -72,8 +77,13 @@ class Registry:
72
77
  """
73
78
  参数:
74
79
  uid: <hashable> 实例的唯一标识符
75
- 默认置空,此时将新建一个实例,并将此时已有实例的数量作为 uid
76
- 当为非空,则根据 uid 到已有实例中寻找相同的实例,并返回(使用该特性可以构造单例模式)
80
+ - 不设置。新建一个实例,并自动分配一个整数作为 uid(一般是此时已有实例的数量-1),
81
+ 并将该实例记录到类变量 instances_of_Registry 中。
82
+ - 设置为 None。新建一个实例,但不记录到类变量 instances_of_Registry 中。
83
+ - 设置为其他值。根据 uid 到类变量 instances_of_Registry 的已有实例中寻找相同的实例,
84
+ 若命中则返回已有实例,若无则以该 uid 新建一个实例并添加到 instances_of_Registry 中。
85
+ (使用该特性可以构造单例模式)
86
+ 默认为不设置。
77
87
  """
78
88
  try:
79
89
  getattr(self, "uid")
@@ -87,8 +97,8 @@ class Registry:
87
97
  self._path_to_collect = []
88
98
  self._item_to_add = []
89
99
  # 记录到 __instances 中
90
- Registry.__instances[self.uid] = self
91
- Registry.__counter += 1
100
+ if self.uid is not None:
101
+ Registry.__instances[self.uid] = self
92
102
 
93
103
  def add(self, obj, name=None, b_force=False, b_execute_now=True):
94
104
  """
@@ -140,7 +150,7 @@ class Registry:
140
150
  b_force=True)
141
151
  # check
142
152
  if not b_force:
143
- inc_node_nums = fndl.count_leaf_node_nums(var=obj) if isinstance(obj, (list, dict)) else 1 # 增加的节点数量
153
+ inc_node_nums = fndl.count_leaf_node_nums(var=obj) if isinstance(obj, (list, dict)) else 1 # 应该增加的节点数量
144
154
  if fndl.count_leaf_node_nums(var=temp) != fndl.count_leaf_node_nums(var=self.database) + inc_node_nums:
145
155
  # print(f'registration failed, name {name} may be a conflict with an '
146
156
  # f'existing member in {[i for i, j in fndl.get_nodes(var=self.database)]}')
@@ -149,13 +159,15 @@ class Registry:
149
159
  self.database = temp
150
160
  return True
151
161
 
152
- def get(self, name, **kwargs):
162
+ def get(self, name, b_pop=False, **kwargs):
153
163
  """
154
164
  获取
155
165
 
156
166
  参数:
157
- name <str> 成员名称
158
- default: 默认值
167
+ name: <str> 成员名称
168
+ b_pop: <boolean> 取值的同时移除该成员
169
+ 默认为 False
170
+ default: 默认值
159
171
  找不到时,若无默认值则报错,否则将返回默认值
160
172
  """
161
173
  # 加载待注册成员
@@ -168,46 +180,7 @@ class Registry:
168
180
  self.collect_from_paths(**i)
169
181
  self._path_to_collect.clear()
170
182
 
171
- try:
172
- return fndl.get_value_by_name(var=self.database, name=name)
173
- except:
174
- if "default" in kwargs:
175
- return kwargs["default"]
176
- else:
177
- raise AssertionError(f'element {name} not exists')
178
-
179
- def pop(self, name, **kwargs):
180
- """
181
- 弹出
182
-
183
- 参数:
184
- name: <str> 成员名称
185
- 名称一定要准确,不能含有模糊的 | 字符
186
- default: 默认值
187
- 找不到时,若无默认值则报错,否则将返回默认值
188
- """
189
- assert "|" not in name, \
190
- f'to pop up a specific member needs to give the exact name, ' \
191
- f'does not support the "|" character with automatic deduction, invalid name: {name}, ' \
192
- f'what you probably want to pop is {name.replace("|", ":")}'
193
- res, b_found = None, False
194
-
195
- def func(_, idx, value):
196
- nonlocal res, b_found
197
- if res is None and idx == name:
198
- res, b_found = value, True
199
- return True
200
- else:
201
- return False
202
-
203
- fndl.traverse(var=self.database, match_cond=func, action_mode="remove", b_use_name_as_idx=True)
204
- if b_found:
205
- return res
206
- else:
207
- if "default" in kwargs:
208
- return kwargs["default"]
209
- else:
210
- raise AssertionError(f'element {name} not exists')
183
+ return fndl.get_value_by_name(var=self.database, name=name, b_pop=b_pop, **kwargs)
211
184
 
212
185
  def clear(self):
213
186
  self.database.clear()
@@ -236,7 +209,7 @@ class Registry:
236
209
 
237
210
  return wrapper
238
211
 
239
- # -------------------- 其他 --------------------- #
212
+ # -------------------- 通过路径添加 --------------------- #
240
213
 
241
214
  def collect_from_paths(self, path_ls=None, path_ls_to_exclude=None, b_execute_now=False):
242
215
  """
@@ -298,5 +271,11 @@ class Registry:
298
271
  if temp is not None:
299
272
  self.database = temp.database
300
273
 
274
+ # -------------------- 其他 --------------------- #
275
+
276
+ @property
277
+ def instances_of_Registry(self):
278
+ return dict(Registry.__instances)
279
+
301
280
 
302
281
  UNIFIED_REGISTRY = Registry(uid="UNIFIED_REGISTRY")
@@ -2,7 +2,7 @@ import random
2
2
  import torch
3
3
  import numpy as np
4
4
  import copy
5
- from kevin_toolbox.computer_science.algorithm.for_nested_dict_list import set_value_by_name, get_value_by_name
5
+ from kevin_toolbox.computer_science.algorithm.for_nested_dict_list import set_value_by_name, get_value_by_name, traverse
6
6
 
7
7
 
8
8
  class Strategy_Manager:
@@ -20,9 +20,9 @@ class Strategy_Manager:
20
20
  ":lr": {
21
21
  # 当 key 满足 trigger_value 时,将 ":lr" 指向的部分替换为 value
22
22
  0: 0.1,
23
- # 如果是以 <f> 为开头的字符串,则视为函数并将 value 解释为函数执行后的结果
23
+ # 如果是以 <eval> 为开头的字符串,则视为函数并将 value 解释为函数执行后的结果
24
24
  # 函数中 t, p 参数将被分别传入 trigger_value 和 para_value
25
- "<f>lambda t: t%100==0": "<f>lambda p, t: p*0.1",
25
+ "<eval>lambda t: t%100==0": "<eval>lambda p, t: p*0.1",
26
26
  },
27
27
  },
28
28
  override=False,
@@ -93,10 +93,11 @@ class Strategy_Manager:
93
93
  300: {
94
94
  ":ratio_ls@1": 1e-5,
95
95
  }, # 在 epoch=300 时,将 ratio_ls[1] 设置为 1e-5
96
- "<f>lambda t: t%100==0": {
97
- ":lr": "<f>lambda p, t: p*0.1",
98
- }, # 当键为 string 且 开头带有 <f> 标记时候,将以函数的方式读取该字符串,
99
- # 并在匹配过程中向该函数输入触发值 t 和当前元素的值 p,当函数返回True视为匹配成功。
96
+ "<eval>lambda t: t%100==0": {
97
+ ":lr": "<eval>lambda p, t: p*0.1",
98
+ }, # 当键为 string 且 开头带有 <eval> 标记时候,将使用 eval() 函数读取该字符串,
99
+ # 当键为 callable 的函数时,在匹配过程中向该函数输入触发值 t 和当前元素的值 p
100
+ # 当函数返回True视为匹配成功。
100
101
  # 比如上式表示的是:每经过 100 epoch,也就是当 epoch%100==0 时,lr 在原来的基础上乘上0.1。
101
102
  # 函数匹配的的优先级低于直接的值匹配。
102
103
  ...
@@ -109,7 +110,7 @@ class Strategy_Manager:
109
110
  "__trigger_name": "epoch",
110
111
  ":lr": {
111
112
  0: 0.1,
112
- "<f>lambda t: t%100==0": "<f>lambda p, t: p*0.1",
113
+ "<eval>lambda t: t%100==0": "<eval>lambda p, t: p*0.1",
113
114
  },
114
115
  ":ratio_ls": {
115
116
  0: [1e-3, 1e-2],
@@ -146,6 +147,21 @@ class Strategy_Manager:
146
147
  temp[t_key][p_key] = strategy[p_key][t_key]
147
148
  strategy = temp
148
149
 
150
+ def deal_eval_str(x):
151
+ return eval(x[6:]) if isinstance(x, (str,)) and x.startswith("<eval>") else x
152
+
153
+ # 使用 eval() 读取带 "<eval>" 标签的键or值
154
+ def converter(_, value):
155
+ if isinstance(value, (dict,)):
156
+ res = {deal_eval_str(k): deal_eval_str(v) for k, v in value.items()}
157
+ else:
158
+ res = deal_eval_str(value)
159
+ return res
160
+
161
+ strategy = traverse(var=[strategy], match_cond=lambda _, __, value: isinstance(value, (dict, str,)),
162
+ action_mode="replace", converter=converter, traversal_mode="dfs_post_order",
163
+ b_use_name_as_idx=False, b_traverse_matched_element=True)[0]
164
+
149
165
  # 将策略添加到 database
150
166
  old_strategy = self.database.get(_trigger_name, dict())
151
167
  for t_key, item in strategy.items():
@@ -187,7 +203,7 @@ class Strategy_Manager:
187
203
  action_s = dict() # {p_name: p_value, ...}
188
204
  # 使用匹配函数
189
205
  for key, p_s in strategy.items():
190
- if isinstance(key, (str,)) and key.startswith("<f>") and eval(key[3:])(t_value):
206
+ if callable(key) and key(t_value):
191
207
  action_s.update({i: j for i, j in p_s.items() if i not in action_s})
192
208
  # 直接匹配
193
209
  if t_value in strategy:
@@ -200,9 +216,9 @@ class Strategy_Manager:
200
216
  for t_name, action_s in sorted(action_s_all.items(), key=lambda x: x[0]):
201
217
  t_value = trigger_state[t_name]
202
218
  for name, p_value in copy.deepcopy(action_s):
203
- if isinstance(p_value, (str,)) and p_value.startswith("<f>"):
219
+ if callable(p_value):
204
220
  raw_value = get_value_by_name(var=var, name=name)
205
- p_value = eval(p_value[3:])(raw_value, t_value)
221
+ p_value = p_value(raw_value, t_value)
206
222
  set_value_by_name(var=var, name=name, value=p_value)
207
223
 
208
224
  return var, action_s_all
@@ -217,7 +233,7 @@ if __name__ == '__main__':
217
233
  "__trigger_name": "epoch",
218
234
  ":lr": {
219
235
  # 0: 0.1,
220
- "<f>lambda t: t%100==0": "<f>lambda p, t: p*0.1",
236
+ "<eval>lambda t: t%100==0": "<eval>lambda p, t: p*0.1",
221
237
  },
222
238
  })
223
239
  sm.add(strategy={
@@ -230,8 +246,8 @@ if __name__ == '__main__':
230
246
  300: {
231
247
  ":ratio_ls@1": 1e-5,
232
248
  },
233
- # "<f>lambda t: t%100==0": {
234
- # ":lr": "<f>lambda p, t: p*0.1",
249
+ # "<eval>lambda t: t%100==0": {
250
+ # ":lr": "<eval>lambda p, t: p*0.1",
235
251
  # },
236
252
  }, override=False)
237
253
 
@@ -1,60 +1,87 @@
1
+ import copy
2
+ from kevin_toolbox.computer_science.algorithm.registration import Registry
3
+ from kevin_toolbox.computer_science.algorithm import for_nested_dict_list as fndl
4
+
5
+
1
6
  class Trigger:
2
- def __init__(self):
7
+ """
8
+ 触发器
9
+ 通过 self.update_by_state() 来接收并监视 state_dict,
10
+ 当 state_dict 全部或部分发生变化时,将会把【发生变化的部分】
11
+ 传入 self.bind() 绑定的函数中,并执行一次该函数。
12
+ """
13
+
14
+ def __init__(self, **kwargs):
3
15
  """
4
- 触发器
5
- 通过 self.update_by_state() 来接收并监视 state_dict,
6
- state_dict 全部或部分发生变化时,将会把【发生变化的部分】
7
- 传入 self.bind() 绑定的函数中,并执行一次该函数。
16
+ 参数:
17
+ target_s: <dict> 待绑定目标
18
+ 以名称 name 为键,以待绑定目标 target 为值
19
+ 主要调用 self.bind()
20
+ init_state <dict> 初始状态
21
+ 默认不设置,此时将在第一次调用 self.update_by_state() 时设置
8
22
  """
23
+ # 默认参数
24
+ paras = {
25
+ #
26
+ "target_s": dict(),
27
+ "init_state": dict()
28
+ }
29
+
30
+ # 获取参数
31
+ paras.update(kwargs)
9
32
 
10
- self.last_state = dict()
11
- self.func_ls = []
33
+ self.last_state = paras["init_state"]
34
+ self.database = Registry(uid=None)
35
+ for k, v in paras["target_s"].items():
36
+ self.bind(name=k, target=v)
12
37
 
13
- def bind_func(self, target):
38
+ def bind(self, name, target):
14
39
  """
15
- 绑定函数
40
+ 绑定触发目标
41
+ 触发目标有以下类型
42
+ - 可以是实例(要求实例具有 update_by_state() 方法,将该方法作为真正的触发目标)
43
+ - 函数
16
44
 
17
45
  参数:
18
- target: <func/list of func>
46
+ name: <str> 名称,具体参见 for_nested_dict_list 中关于 name 的介绍
47
+ target: <obj/func> 待绑定目标
19
48
  """
20
- target = [target] if not isinstance(target, (list, tuple,)) else target
21
- for func in target:
22
- assert callable(func)
23
- self.func_ls.extend(target)
49
+ func = getattr(target, "update_by_state", None)
50
+ target = target if func is None else func
51
+ assert callable(target), \
52
+ f'object {target} is not callable and has no update_by_state() method to be bound'
53
+ assert isinstance(name, (str,))
24
54
 
25
- def bind_obj(self, target):
55
+ self.database.add(obj=target, name=name, b_force=True, b_execute_now=True)
56
+
57
+ def unbind(self, name, b_not_exist_ok=True):
26
58
  """
27
- 绑定实例
28
- 要求实例具有 update_by_state() 方法
59
+ 接触绑定
29
60
 
30
61
  参数:
31
- target: <func/list of obj>
32
- """
33
- target = [target] if not isinstance(target, (list, tuple,)) else target
34
- temp = []
35
- for i in target:
36
- func = getattr(i, "update_by_state", None)
37
- assert callable(func), \
38
- f'there is no update_by_state() method in the object {i} to be bound'
39
- temp.append(func)
40
- self.func_ls.extend(temp)
41
-
42
- def bind(self, target):
43
- """
44
- 依次尝试通过 bind_func() 和 bind_obj() 方法对 target 进行绑定
62
+ name: <str> 待接触绑定目标的名称
63
+ b_not_exist_ok: <boolean> name 不存在时是否不报错
64
+ 默认为 True,不报错
45
65
  """
46
- target = [target] if not isinstance(target, (list, tuple,)) else target
47
- for i in target:
48
- try:
49
- self.bind_func(target=i)
50
- except:
51
- self.bind_obj(target=i)
52
-
53
- def update_by_state(self, cur_state):
66
+
67
+ try:
68
+ self.database.get(name=name, b_pop=True)
69
+ except:
70
+ if not b_not_exist_ok:
71
+ raise IndexError(f'name {name} not exists')
72
+
73
+ def update_by_state(self, cur_state, target_names=None):
54
74
  """
55
75
  更新状态,决定是否触发
76
+
77
+ 参数:
78
+ cur_state: <dict> 状态
79
+ target_names: <list of str> 需要更新的目标
80
+ 默认为 None,此时将更新所有目标
56
81
  """
57
82
  assert isinstance(cur_state, (dict,))
83
+ target_names = [""] if target_names is None else target_names
84
+ assert isinstance(target_names, (list,))
58
85
 
59
86
  new_state = dict()
60
87
  for key, value in cur_state.items():
@@ -62,8 +89,35 @@ class Trigger:
62
89
  new_state[key] = value
63
90
 
64
91
  if len(new_state) > 0:
65
- for func in self.func_ls:
66
- func(new_state)
92
+ # get funcs to update
93
+ func_s = dict()
94
+ for target_name in target_names:
95
+ var = self.database.get(name=target_name, b_pop=False, default=None)
96
+ if isinstance(var, (list, dict,)):
97
+ func_s.update({target_name + k: v for k, v in fndl.get_nodes(var=var, level=-1, b_strict=True)})
98
+ else:
99
+ func_s[target_name] = var
100
+ # update
101
+ for func in func_s.values():
102
+ if func is not None:
103
+ func(new_state)
67
104
  self.last_state.update(new_state)
68
105
 
69
106
  return new_state
107
+
108
+ # ---------------------- 用于保存和加载触发器的状态 ---------------------- #
109
+
110
+ def load_state_dict(self, state_dict):
111
+ """
112
+ 加载触发器状态
113
+ """
114
+ self.last_state = state_dict["last_state"]
115
+
116
+ def state_dict(self):
117
+ """
118
+ 获取触发器状态
119
+ """
120
+ return {"last_state": copy.deepcopy(self.last_state)}
121
+
122
+ def clear_state_dict(self):
123
+ self.last_state.clear()
@@ -49,9 +49,11 @@ def check_consistency(*args, tolerance=1e-7, require_same_shape=True):
49
49
  for i, j in zip(args[0].reshape(-1), v.reshape(-1)):
50
50
  temp = i == j
51
51
  if isinstance(temp, (bool,)):
52
- assert temp
52
+ assert temp, \
53
+ f"{args[0]}, {v}, diff: {temp}"
53
54
  else:
54
- assert temp.all()
55
+ assert temp.all(), \
56
+ f"{args[0]}, {v}, diff: {temp}"
55
57
  else:
56
58
  raise ValueError
57
59
 
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.1
2
+ Name: kevin-toolbox-dev
3
+ Version: 1.1.3
4
+ Summary: 一个常用的工具代码包集合
5
+ Home-page: https://github.com/cantbeblank96/kevin_toolbox
6
+ Download-URL: https://github.com/username/your-package/archive/refs/tags/v1.0.0.tar.gz
7
+ Author: kevin hsu
8
+ Author-email: xukaiming1996@163.com
9
+ License: MIT
10
+ Keywords: mathematics,pytorch,numpy,machine-learning,algorithm
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.6
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: torch (>=1.2.0)
17
+ Requires-Dist: numpy (>=1.19.0)
18
+ Provides-Extra: plot
19
+ Requires-Dist: matplotlib (>=3.0) ; extra == 'plot'
20
+ Provides-Extra: rest
21
+ Requires-Dist: pytest (>=6.2.5) ; extra == 'rest'
22
+ Requires-Dist: line-profiler (>=3.5) ; extra == 'rest'
23
+
24
+ # kevin_toolbox
25
+
26
+ 一个通用的工具代码包集合
27
+
28
+
29
+
30
+ 环境要求
31
+
32
+ ```shell
33
+ numpy>=1.19
34
+ pytorch>=1.2
35
+ ```
36
+
37
+ 安装方法:
38
+
39
+ ```shell
40
+ pip install kevin-toolbox --no-dependencies
41
+ ```
42
+
43
+
44
+
45
+ [项目地址 Repo](https://github.com/cantbeblank96/kevin_toolbox)
46
+
47
+ [使用指南 User_Guide](./notes/User_Guide.md)
48
+
49
+ [免责声明 Disclaimer](./notes/Disclaimer.md)
50
+
51
+ [版本更新记录](./notes/Release_Record.md):
52
+
53
+ - v 1.1.3(2023-06-30)
54
+ - computer_science.algorithm.for_nested_dict_list
55
+ - 在 traverse() 中新增了traversal_mode 参数用于控制遍历的顺序,目前支持三种模式: "dfs_pre_order" 深度优先-先序遍历、"dfs_post_order" 深度优先-后序遍历、以及 "bfs" 宽度优先。
56
+ - 在单元测试中新增了对 traverse() 中 traversal_mode 参数的测试项目。
57
+ - value_parser
58
+ - 修改 eval_references() 中 converter_for_ref 参数的行为,从原来只是作为计算结果前对算式中引用节点值的预处理,变成直接改变被引用节点的值。亦即原来不会修改原被引用节点的值,现在变为会修改原节点的值了。
59
+ - computer_science.algorithm.scheduler
60
+ - 改进 Strategy_Manager
61
+ - 使用 `<eval>` 来标记需要使用 eval() 函数读取的字符串。相对于旧版通过 `<eval>` 来标记需要被读取为函数的字符串,使用 `<eval>` 不仅可以读取函数,也可以读取更多的数据结构。
62
+ - 在通过 add() 添加策略时即对 strategy 中被 `<eval>` 标记的键值进行解释,而非等到后续每次 cal() 时再进行解释,提高了效率。
63
+ - 修改了对应的单元测试。
@@ -1,4 +1,4 @@
1
- kevin_toolbox/__init__.py,sha256=DFpREPfEjN9P8LPXS5zxzqv3ubGbXwB1AQYyOAF5Hdc,410
1
+ kevin_toolbox/__init__.py,sha256=vAS6Ot-u8d3-594niDe3hf21gjSztypz4qspgIG4jNU,410
2
2
  kevin_toolbox/computer_science/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  kevin_toolbox/computer_science/algorithm/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
4
4
  kevin_toolbox/computer_science/algorithm/combinatorial_optimization/__init__.py,sha256=fBMX0_WiV8kfHLWZNfVe2uL67gsN_oHfpbuHaHUOiys,142
@@ -10,20 +10,20 @@ kevin_toolbox/computer_science/algorithm/combinatorial_optimization/test/test_ze
10
10
  kevin_toolbox/computer_science/algorithm/for_dict/__init__.py,sha256=YFxhbWIsOMGf7ay3fh0sosvXzpuqQQC1bkXK75LAqO4,37
11
11
  kevin_toolbox/computer_science/algorithm/for_dict/deep_update.py,sha256=_1GL8-zY1t48rp3N_SiirjYPzLwQSN_cpmzLKymOnQI,666
12
12
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/__init__.py,sha256=tOEHNkIRhCMTjAaNNjn_Wa6FXNvQTyNC2erJN0rpLkw,273
13
- kevin_toolbox/computer_science/algorithm/for_nested_dict_list/copy_.py,sha256=NQp6sq2yPJQ--PfV9vgtIMkgjRNmGk1gtpKAn-dRYsc,887
13
+ kevin_toolbox/computer_science/algorithm/for_nested_dict_list/copy_.py,sha256=vOHiHg8UHnETy5e3hODzSnGHGMlxcFml4Q1qbX88aEI,939
14
14
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/count_leaf_node_nums.py,sha256=CY9fXmdkwWqHwP62LyxCp7uqt5OMNcSm1zD4s4Ol_x0,645
15
15
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/get_hash.py,sha256=Ygadnn5dnvIeE-9t39p2EwNKNRLzomL37ZsRD5daXxo,1286
16
16
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/get_nodes.py,sha256=tpRAE3p_ER9Kj4GwP7ub_ZYm_qITRxAzom2t2EHUyms,3543
17
- kevin_toolbox/computer_science/algorithm/for_nested_dict_list/get_value_by_name.py,sha256=Jy-HcRdQSdcCvIVpSXJ0QCMX7HGMNLllPt8aRk43zCM,1303
18
- kevin_toolbox/computer_science/algorithm/for_nested_dict_list/set_value_by_name.py,sha256=Bqqewcli6MdLkAtRHxh8B8IYr1vkMoL3K5-_FVb22p0,2842
19
- kevin_toolbox/computer_science/algorithm/for_nested_dict_list/traverse.py,sha256=mBWHsEKYRGqEeQ1h6fD6FbwW_UO67GOARS33wB_GhuI,3951
17
+ kevin_toolbox/computer_science/algorithm/for_nested_dict_list/get_value_by_name.py,sha256=MlpfZrr95VrZgKpjV_CtJSc7LG1l79_5JUJ6_phwVxo,2122
18
+ kevin_toolbox/computer_science/algorithm/for_nested_dict_list/set_value_by_name.py,sha256=aFZL5P9C3kbJEfNBNgr760B7mYWSunirjTU-EpglGbk,2875
19
+ kevin_toolbox/computer_science/algorithm/for_nested_dict_list/traverse.py,sha256=3g--9_icGWN2CuXu1qXyzsCxovf0UymutD3_C2DJkP4,6889
20
20
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/name_handler/__init__.py,sha256=P_pWq78oN6NdvWg2h6AduW_sUqbeaaVyoWWbW9kbgmU,107
21
21
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/name_handler/build_name.py,sha256=63xfhk1-lUButEdn76I32Sx-osvKF8A8KJBNylA2QBI,1051
22
22
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/name_handler/escape_node.py,sha256=niT9MxmsyrSZYhKXlWzdoKXVYhWRCR-kmQBkZopznpA,1163
23
23
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/name_handler/parse_name.py,sha256=bk1vdBIX07Nu52hd805GqIWj51vnaJiq-owBAJGP-O4,2350
24
24
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/value_parser/__init__.py,sha256=9Z-zlaCakJsb8oB_ZpzUGxdH743gmoXrwJJCTP1viLY,169
25
25
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/value_parser/cal_relation_between_references.py,sha256=csxrOB_QZIOlTJo9-buBOkEwyE2mGRbq2_dzvXwkNjs,3181
26
- kevin_toolbox/computer_science/algorithm/for_nested_dict_list/value_parser/eval_references.py,sha256=XWApZnrMaS8HEZ4UOb1J41BW9DkIwJgqhqoDK8BFC0w,1737
26
+ kevin_toolbox/computer_science/algorithm/for_nested_dict_list/value_parser/eval_references.py,sha256=Dx4tAu51wRqTTQlYOw2NrGszxPnMukbIDbXY74P-CIc,2372
27
27
  kevin_toolbox/computer_science/algorithm/for_nested_dict_list/value_parser/parse_references.py,sha256=SYmJSC8IO-6VlCT1BlM9924kEuRbO4rGEN8hpPjlDhc,2155
28
28
  kevin_toolbox/computer_science/algorithm/for_seq/__init__.py,sha256=qXNVulpOBOWlD2yJ9L4D5bfrNFmnBd29ibtUbvaJHYk,76
29
29
  kevin_toolbox/computer_science/algorithm/for_seq/flatten_list.py,sha256=XnDq-_nQln55vwpAnBslyOKI_KYq11C7PmfLChhSe0k,1046
@@ -33,10 +33,10 @@ kevin_toolbox/computer_science/algorithm/locks/mutex_lock.py,sha256=81cCw3oTXCZx
33
33
  kevin_toolbox/computer_science/algorithm/pareto_front/__init__.py,sha256=LbeaSzG0hkx8NHAlzvEalrGi2WufaXguVfeBRzaw-MA,57
34
34
  kevin_toolbox/computer_science/algorithm/pareto_front/get_pareto_points_idx.py,sha256=a-8Js-dpkuVu9MsImW9hwHp9OTC278xo9oJP96oX0Io,2712
35
35
  kevin_toolbox/computer_science/algorithm/registration/__init__.py,sha256=teEd9HkrB6baLpwNwae5c4wn0QRwV3KtBv-2V9-Z7cc,49
36
- kevin_toolbox/computer_science/algorithm/registration/registry.py,sha256=v0XcH8Rde31OvrZ9C3rBfL0FY8GvHUc-u1OJ1RexHN0,13982
36
+ kevin_toolbox/computer_science/algorithm/registration/registry.py,sha256=Luz48VmqS8BR8sjwQrfHnI0biAYv06rG8ZyXTskPvfA,13567
37
37
  kevin_toolbox/computer_science/algorithm/scheduler/__init__.py,sha256=ENzZsNaMu6ISilTxeE3_EP_L0dNi8SI7IYdTdxic2nw,76
38
- kevin_toolbox/computer_science/algorithm/scheduler/strategy_manager.py,sha256=yVOLk_k-V_RN7GMTx2-fL4eXbHa-DQDnIbmbpvGamyc,11495
39
- kevin_toolbox/computer_science/algorithm/scheduler/trigger.py,sha256=dCKX2f8aPtzE88-upbcuyNRpe3nx8CK2T9CM1lW7_iU,2203
38
+ kevin_toolbox/computer_science/algorithm/scheduler/strategy_manager.py,sha256=nzKLaKOmIAc6Hrm1O6KAm49yvJtIWMUY-gaswslkIb4,12265
39
+ kevin_toolbox/computer_science/algorithm/scheduler/trigger.py,sha256=WDkM635xcB3ZoPzOCJUwLHju22Fuji7PA7xCx-ZQLOI,4508
40
40
  kevin_toolbox/computer_science/algorithm/search/__init__.py,sha256=zja7FXLTNd2dSVzzGp1TbBp4i3TDY8S9tcJ9pqc684A,41
41
41
  kevin_toolbox/computer_science/algorithm/search/binary_search.py,sha256=FcOdgxfuNews_AhPF_CoQDr2vBPqpUpifF7Fmgml1p4,1013
42
42
  kevin_toolbox/computer_science/algorithm/statistician/__init__.py,sha256=zW1zesXYNjh6cAZPz_gsXd2LEEPlvA7SNB0huCb9WCg,120
@@ -207,7 +207,7 @@ kevin_toolbox/patches/for_optuna/sample_from_feasible_domain.py,sha256=v_qrPPWE2
207
207
  kevin_toolbox/patches/for_os/__init__.py,sha256=mdbhe6Nvgbkt8v960ATmnKtF-4ds94yIU0-k3k14dHc,27
208
208
  kevin_toolbox/patches/for_os/remove.py,sha256=ji71D3BQA8g-xZr7IMRD9ANXfdsszS9QXDopAfVHfnw,658
209
209
  kevin_toolbox/patches/for_test/__init__.py,sha256=sFr2VZD1zk8Vtjq2_F8uE4xNovJF6yDY8j1YND5XAw0,49
210
- kevin_toolbox/patches/for_test/check_consistency.py,sha256=-A2VYECmLzGHkAWavPNbpZBT9Nsdm4nlNOkmX5CBwLo,3066
210
+ kevin_toolbox/patches/for_test/check_consistency.py,sha256=gSss0OUwpp4WqD08iUiuIjyNVGTGw77jSt-RqDMgQ_A,3184
211
211
  kevin_toolbox/patches/for_torch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
212
212
  kevin_toolbox/patches/for_torch/compatible/__init__.py,sha256=7l4FPTILBR8EmStJNHIsbwfFkZpe4xkJZtrlyC8riL8,75
213
213
  kevin_toolbox/patches/for_torch/compatible/concat.py,sha256=vFJn9B437gxDOa5Ze_gXxZewiClqoiIkWeAktDEcJK4,393
@@ -223,7 +223,7 @@ kevin_toolbox/patches/for_torch/math/get_y_at_x.py,sha256=bfoVcasZ_tMdhR_1Me0Jli
223
223
  kevin_toolbox/patches/for_torch/math/my_around.py,sha256=ptpU3ids50gwf663EpHbw7raj9tNrDGBFZ5t_uMNH14,1378
224
224
  kevin_toolbox/patches/for_torch/nn/__init__.py,sha256=aJs3RMqRzQmd8KKDmQW9FxwCqS5yfPqEdg-m0PwlQro,39
225
225
  kevin_toolbox/patches/for_torch/nn/lambda_layer.py,sha256=KUuLiX_Dr4bvRmpAaCW5QTDWDcnMPRnw0jg4NNXTFhM,223
226
- kevin_toolbox_dev-1.1.1.dist-info/METADATA,sha256=pwrwgslJERvXHu0fBaI_YoTbzaOG5wCTaMCwaPKiQEQ,5453
227
- kevin_toolbox_dev-1.1.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
228
- kevin_toolbox_dev-1.1.1.dist-info/top_level.txt,sha256=S5TeRGF-PwlhsaUEPTI-f2vWrpLmh3axpyI6v-Fi75o,14
229
- kevin_toolbox_dev-1.1.1.dist-info/RECORD,,
226
+ kevin_toolbox_dev-1.1.3.dist-info/METADATA,sha256=-D6TRFBMXRFA2QT9wyr4Zz4sF5TrKmGrKs8gIPHEI24,2494
227
+ kevin_toolbox_dev-1.1.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
228
+ kevin_toolbox_dev-1.1.3.dist-info/top_level.txt,sha256=S5TeRGF-PwlhsaUEPTI-f2vWrpLmh3axpyI6v-Fi75o,14
229
+ kevin_toolbox_dev-1.1.3.dist-info/RECORD,,
@@ -1,127 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: kevin-toolbox-dev
3
- Version: 1.1.1
4
- Summary: 一个常用的工具代码包集合
5
- Home-page: https://github.com/cantbeblank96/kevin_toolbox
6
- Download-URL: https://github.com/username/your-package/archive/refs/tags/v1.0.0.tar.gz
7
- Author: kevin hsu
8
- Author-email: xukaiming1996@163.com
9
- License: MIT
10
- Keywords: mathematics,pytorch,numpy,machine-learning,algorithm
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python
13
- Classifier: Programming Language :: Python :: 3
14
- Requires-Python: >=3.6
15
- Description-Content-Type: text/markdown
16
- Requires-Dist: torch (>=1.2.0)
17
- Requires-Dist: numpy (>=1.19.0)
18
- Provides-Extra: plot
19
- Requires-Dist: matplotlib (>=3.0) ; extra == 'plot'
20
- Provides-Extra: rest
21
- Requires-Dist: pytest (>=6.2.5) ; extra == 'rest'
22
- Requires-Dist: line-profiler (>=3.5) ; extra == 'rest'
23
-
24
- # kevin_toolbox
25
-
26
- 一个通用的工具代码包集合
27
-
28
-
29
-
30
- 环境要求
31
-
32
- ```shell
33
- numpy>=1.19
34
- pytorch>=1.2
35
- ```
36
-
37
- 安装方法:
38
-
39
- ```shell
40
- pip install kevin-toolbox --no-dependencies
41
- ```
42
-
43
-
44
-
45
- [项目地址 Repo](https://github.com/cantbeblank96/kevin_toolbox)
46
-
47
- [使用指南 User_Guide](./notes/User_Guide.md)
48
-
49
- [免责声明 Disclaimer](./notes/Disclaimer.md)
50
-
51
- [版本更新记录](./notes/Release_Record.md):
52
-
53
- - v 1.1.0(2023-06-21)【bug fix】
54
- - computer_science.algorithm.for_dict
55
- - fix bug in deep_update(),修复了无法更新stem中值为None的部分的问题。
56
- - 添加了单元测试
57
-
58
- - computer_science.algorithm.for_nested_dict_list
59
-
60
- - 新增模块 name_handler 用于处理名字的解释、构造等
61
-
62
- - parse_name() 解释名字 name 得到:root_node、取值方式 method_ls 、取值时使用的键 node_ls
63
- - build_name() 根据root_node、取值方式 method_ls 、取值时使用的键 node_ls,来构造名字 name
64
- - escape_node() 对键进行转义/反转义
65
- - 添加了单元测试
66
- - 添加了说明文档
67
- - 支持了转义字符。对于含有特殊字符 :|@ 的 node,可以对 node 中的这些特殊字符使用 \ 进行转义,避免将这些字符解释为取值方式。
68
-
69
- - 结合 name_handler 修改了 get_value_by_name()、get_nodes()、traverse()、set_value_by_name()
70
-
71
- - 改进了 set_value_by_name(),支持强制创建列表
72
-
73
- - 新增模块 value_parser 用于处理带有引用的值
74
-
75
- - 什么是引用?
76
-
77
- - 对于值,若为字符串类型,且其中含有 `"...<flag>{ref_name}..."` 的形式,则表示解释该值时需要将 `<flag>{ref_name}` 这部分替换为 var 中 ref_name 对应的值
78
-
79
- - parse_references() 解释 var 中包含引用的值
80
-
81
- - ```
82
- 比如对于:
83
- name=":z", value="<v>{:x}+<v>{:y}"
84
- 的节点,将会返回:
85
- {":z": {"expression":"p_0+p_1" , "paras": {"p_0":":x","p_1":":y"}}, ...}
86
- 利用 "expression" 和 "paras" 中的内容,将可以很方便得使用 eval() 和 get_value_by_name() 完成对节点值的计算。
87
- 但是由于节点之间可能存在相互引用,因此一般需要通过 cal_relation_between_references() 来确定计算顺序。
88
- ```
89
-
90
- - cal_relation_between_references() 计算具有引用的节点之间的关系
91
-
92
- - ```
93
- 函数返回值:
94
- node_s, b_is_DAG, order
95
-
96
- node_s: <dict> 在输入的 node_s 的基础上为每个节点补充 upstream_node 和 downstream_node 字段
97
- 其中:
98
- upstream_node 中保存该节点所依赖的上游节点,意味着要等这些上游节点计算完毕后才能计算该节点
99
- downstream_node 中保存对该节点有依赖的下游节点。
100
- b_is_DAG: <boolean> 节点关系是否满足有向无环图 DAG
101
- order: <list of name> 节点在 DAG 中的顺序
102
- ```
103
-
104
- - eval_references() 将 var 中的具有引用的值替换为计算结果
105
-
106
- - data_flow.file.kevin_notation
107
-
108
- - 修改 write_contents() 支持通过 b_single_line 参数来明确指定是使用单行or多行模式进行写入
109
- - 修改 `__setattr__()` 支持通过前缀 "row_ls" or "column_dict" 来指定写入内容的组织形式,支持通过添加后缀 "single_line" or "multi_line" 来明确指定按照单行or多行模式进行写入
110
- - 例如 self.row_ls_single_line = value 等效于 self.write_contents(row_ls=value, b_single_line=True)
111
-
112
- - computer_science.algorithm.registration
113
-
114
- - 改进 Registry 类
115
- - 在 add() 中也增加了b_execute_now 来控制延时导入
116
- - 在 collect_from_paths() 中新增了 path_ls_to_exclude 参数用于指定需要排除的目录
117
- - 改进了 collect_from_paths() 中路径的搜索方式,改为从深到浅导入,可以避免继承引起的 TypeError: super(type, obj) 类型错误
118
-
119
- - computer_science.algorithm.scheduler
120
-
121
- - 修改 Trigger 类中的 bind() 方法,支持直接读取实例的 update_by_state() 函数进行绑定。同时也新增了 bind_func() 和 bind_obj() 用于在明确待绑定对象类型时使用。
122
-
123
- - v 1.1.1(2023-06-21)
124
-
125
- - computer_science.algorithm.for_nested_dict_list.value_parser
126
- - 在 eval_references() 中新增了参数 converter_for_ref 和 converter_for_res 用于指定对 引用值 和 计算结果 施加何种处理
127
-