qudas 0.1.0__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.
qudas/__init__.py ADDED
@@ -0,0 +1,21 @@
1
+ # __init__.py
2
+
3
+ # バージョン情報をVERSIONファイルから読み込む
4
+ import os
5
+
6
+ # VERSIONファイルのパスを絶対パスで取得
7
+ VERSION_FILE_PATH = os.path.join(
8
+ os.path.dirname(os.path.abspath(__file__)), '..', 'VERSION'
9
+ )
10
+
11
+ # VERSIONファイルからバージョンを読み込む
12
+ try:
13
+ with open(VERSION_FILE_PATH) as version_file:
14
+ __version__ = version_file.read().strip()
15
+ except FileNotFoundError:
16
+ __version__ = '0.0.1' # デフォルトバージョンを設定
17
+
18
+ from .qudata import QuData
19
+ from .pipeline import Pipeline
20
+
21
+ __all__ = ['QuData', 'Pipeline']
@@ -0,0 +1,3 @@
1
+ # pipeline/__init__.py
2
+
3
+ from .pipeline import Pipeline
@@ -0,0 +1,457 @@
1
+ from typing import Sequence, Dict, Any, Tuple, Optional
2
+ from .steps import IteratorMixin
3
+
4
+
5
+ class Pipeline:
6
+ def __init__(
7
+ self, steps: Sequence[Tuple[str, Any]], iterator: Optional[IteratorMixin] = None
8
+ ) -> None:
9
+ """
10
+ Pipelineクラスは一連のステップを受け取り、それぞれのステップを順に実行する。
11
+
12
+ Args:
13
+ steps (Sequence[Tuple[str, Any]]): ステップのリスト。各ステップは (名前, オブジェクト) のタプル形式。
14
+ iterator (Optional[IteratorMixin]): Pipeline全体を繰り返すイテレータ。イテレータは IteratorMixin 形式。デフォルト値はNone。
15
+ """
16
+ self.steps = steps
17
+ self.models = {step_name: None for step_name, _ in steps}
18
+ self.results = {step_name: None for step_name, _ in steps}
19
+ self.global_params = {}
20
+ self.global_iterator = iterator
21
+
22
+ def set_global_params(self, params: Dict[str, Any]) -> None:
23
+ """
24
+ パイプライン全体に適用するグローバルパラメータを設定する。
25
+
26
+ Args:
27
+ params (Dict[str, Any]): グローバルパラメータ。
28
+ """
29
+ self.global_params = params
30
+
31
+ def get_global_params(self) -> Dict[str, Any]:
32
+ """
33
+ パイプライン全体に適用されたグローバルパラメータを取得する。
34
+
35
+ Returns:
36
+ Dict[str, Any]: グローバルパラメータ。
37
+ """
38
+ return self.global_params
39
+
40
+ def _assign_global_params(self, step_instance):
41
+ """ステップが global_params を自動的に持つようにする"""
42
+ if not hasattr(step_instance, 'set_global_params'):
43
+ step_instance.global_params = self.global_params
44
+ else:
45
+ step_instance.set_global_params(self.global_params)
46
+
47
+ # models と results を共有
48
+ step_instance.models = self.models
49
+ step_instance.results = self.results
50
+
51
+ def _update_params(self, step_instance):
52
+ """パラメータを更新"""
53
+ if hasattr(step_instance, 'get_global_params'):
54
+ self.global_params = step_instance.get_global_params()
55
+
56
+ def _process_step(self, step: Tuple[str, Any], X: Any, y: Any, mode: str) -> Any:
57
+ """
58
+ ステップを実行する。
59
+
60
+ Args:
61
+ step (Tuple[str, Any]): 現在のステップ。
62
+ X (Any): 入力データ。
63
+ y (Any): ターゲットデータ。
64
+ mode (str): 実行モード ('fit', 'transform', 'optimize', 'predict')。
65
+
66
+ Returns:
67
+ Any: ステップまたはモデルによって処理されたデータ。
68
+ """
69
+ step_name, step_instance = step
70
+ model = self.models.get(step_name)
71
+
72
+ # モデルが存在し、transformまたはpredictを実行可能な場合
73
+ if model:
74
+ if mode == 'transform' and hasattr(model, 'transform'):
75
+ return model.transform(X)
76
+ if mode == 'predict' and hasattr(model, 'predict'):
77
+ return model.predict(X)
78
+
79
+ # モデルがない場合、通常のステップ処理
80
+ if mode == 'transform':
81
+ if hasattr(step_instance, 'transform'):
82
+ return step_instance.transform(X)
83
+ else:
84
+ return X
85
+
86
+ elif mode == 'fit' and hasattr(step_instance, 'fit'):
87
+ return step_instance.fit(X, y)
88
+
89
+ elif mode == 'optimize' and hasattr(step_instance, 'optimize'):
90
+ return step_instance.optimize(X, y)
91
+
92
+ return None
93
+
94
+ def fit(self, X: Any, y: Any = None) -> 'Pipeline':
95
+ """
96
+ 各ステップを順に適用してデータを訓練する。
97
+
98
+ Args:
99
+ X (Any): 入力データ。
100
+ y (Any): ターゲットデータ。
101
+
102
+ Returns:
103
+ Pipeline: パイプラインオブジェクト自身。
104
+
105
+ Raises:
106
+ RuntimeError: 最後のステップに fit メソッドがない場合。
107
+ """
108
+
109
+ # 全体のglobal_iteratorのループ回数を取得
110
+ global_loop_num = getattr(self.global_iterator, 'loop_num', 1)
111
+
112
+ while global_loop_num > 0:
113
+
114
+ # self.stepsで処理
115
+ for step in self.steps:
116
+ step_name, step_instance = step
117
+
118
+ # 各ステップごとのループ回数を取得 (IteratorMixinのloop_num)
119
+ step_loop_num = getattr(step_instance, 'loop_num', 1)
120
+
121
+ while step_loop_num > 0:
122
+ X = self._process_step(step, X, y, 'transform')
123
+
124
+ # optimize を実行し、結果を y に格納
125
+ if hasattr(step_instance, 'optimize'):
126
+
127
+ # パラメータをstepと共有(処理前)
128
+ self._assign_global_params(step_instance)
129
+
130
+ self.results[step_name] = self._process_step(
131
+ step, X, y, 'optimize'
132
+ )
133
+
134
+ # パラメータをstepと共有(処理後)
135
+ step_instance.results = self.results
136
+ self._update_params(step_instance)
137
+
138
+ if (
139
+ global_loop_num == 1
140
+ and step_loop_num == 1
141
+ and step_name == self.steps[-1][0]
142
+ ):
143
+
144
+ # fit を実行し、モデルを保存
145
+ if hasattr(step_instance, 'fit'):
146
+
147
+ # パラメータをstepと共有(処理前)
148
+ self._assign_global_params(step_instance)
149
+
150
+ self.models[step_name] = self._process_step(
151
+ step, X, y, 'fit'
152
+ )
153
+
154
+ # パラメータをstepと共有(処理後)
155
+ step_instance.models = self.models
156
+ self._update_params(step_instance)
157
+
158
+ else:
159
+ # optimize メソッドが見つからなかった場合のエラー
160
+ raise RuntimeError(
161
+ "パイプラインの最後のステップに fit メソッドが見つかりませんでした。"
162
+ )
163
+
164
+ else:
165
+ # fit を実行し、モデルを保存
166
+ if hasattr(step_instance, 'fit'):
167
+
168
+ # パラメータをstepと共有(処理前)
169
+ self._assign_global_params(step_instance)
170
+
171
+ self.models[step_name] = self._process_step(
172
+ step, X, y, 'fit'
173
+ )
174
+
175
+ # パラメータをstepと共有(処理後)
176
+ step_instance.models = self.models
177
+ self._update_params(step_instance)
178
+
179
+ # next_params が定義されていれば、次のパラメータを取得
180
+ if hasattr(step_instance, 'next_params'):
181
+
182
+ # パラメータをstepと共有
183
+ self._assign_global_params(step_instance)
184
+
185
+ X, y = step_instance.next_params(X, y)
186
+ self._update_params(step_instance)
187
+
188
+ # ステップごとのループ回数をデクリメント
189
+ step_loop_num -= 1
190
+
191
+ # next_params が定義されていれば、次のパラメータを取得
192
+ if hasattr(self.global_iterator, 'next_params'):
193
+
194
+ # パラメータをstepと共有
195
+ self._assign_global_params(self.global_iterator)
196
+
197
+ X, y = self.global_iterator.next_params(X, y)
198
+ self._update_params(self.global_iterator)
199
+
200
+ # ステップごとのループ回数をデクリメント
201
+ global_loop_num -= 1
202
+
203
+ return self
204
+
205
+ def optimize(self, X: Any = None, y: Any = None) -> Dict[str, Any]:
206
+ """
207
+ 各ステップを順に適用して最適化を実行する。
208
+
209
+ Args:
210
+ X (Any): 入力データ。
211
+ y (Any): ターゲットデータ。
212
+
213
+ Returns:
214
+ Dict[str, Any]: 各ステップの最適化結果。
215
+
216
+ Raises:
217
+ RuntimeError: 最後のステップに optimize メソッドがない場合。
218
+ """
219
+
220
+ # 全体のglobal_iteratorのループ回数を取得
221
+ global_loop_num = getattr(self.global_iterator, 'loop_num', 1)
222
+
223
+ while global_loop_num > 0:
224
+
225
+ # self.stepsで処理
226
+ for step in self.steps:
227
+ step_name, step_instance = step
228
+
229
+ # 各ステップのループ回数を取得 (IteratorMixinのloop_num)
230
+ step_loop_num = getattr(step_instance, 'loop_num', 1)
231
+
232
+ while step_loop_num > 0:
233
+
234
+ # Transformer
235
+ X = self._process_step(step, X, y, 'transform')
236
+
237
+ # Estimator
238
+ if hasattr(step_instance, 'fit'):
239
+
240
+ # パラメータをstepと共有(処理前)
241
+ self._assign_global_params(step_instance)
242
+
243
+ self.models[step_name] = self._process_step(step, X, y, 'fit')
244
+
245
+ # パラメータをstepと共有(処理後)
246
+ step_instance.models = self.models
247
+ self._update_params(step_instance)
248
+
249
+ if (
250
+ global_loop_num == 1
251
+ and step_loop_num == 1
252
+ and step_name == self.steps[-1][0]
253
+ ):
254
+
255
+ # Optimizer
256
+ if hasattr(step_instance, 'optimize'):
257
+
258
+ # パラメータをstepと共有(処理前)
259
+ self._assign_global_params(step_instance)
260
+
261
+ self.results[step_name] = self._process_step(
262
+ step, X, y, 'optimize'
263
+ )
264
+
265
+ # パラメータをstepと共有(処理後)
266
+ step_instance.results = self.results
267
+ self._update_params(step_instance)
268
+
269
+ return self.results
270
+
271
+ else:
272
+ # optimize メソッドが見つからなかった場合のエラー
273
+ raise RuntimeError(
274
+ "パイプラインの最後のステップに optimize メソッドが見つかりませんでした。"
275
+ )
276
+
277
+ else:
278
+ # Optimizer
279
+ if hasattr(step_instance, 'optimize'):
280
+
281
+ # パラメータをstepと共有(処理前)
282
+ self._assign_global_params(step_instance)
283
+
284
+ self.results[step_name] = self._process_step(
285
+ step, X, y, 'optimize'
286
+ )
287
+
288
+ # パラメータをstepと共有(処理後)
289
+ step_instance.results = self.results
290
+ self._update_params(step_instance)
291
+
292
+ # next_params が定義されていれば、次のパラメータを取得
293
+ if hasattr(step_instance, 'next_params'):
294
+
295
+ # パラメータをstepと共有
296
+ self._assign_global_params(step_instance)
297
+
298
+ X, y = step_instance.next_params(X, y)
299
+ self._update_params(step_instance)
300
+
301
+ # ステップごとのループ回数をデクリメント
302
+ step_loop_num -= 1
303
+
304
+ # next_params が定義されていれば、次のパラメータを取得
305
+ if hasattr(self.global_iterator, 'next_params'):
306
+
307
+ # パラメータをstepと共有
308
+ self._assign_global_params(self.global_iterator)
309
+
310
+ X, y = self.global_iterator.next_params(X, y)
311
+ self._update_params(self.global_iterator)
312
+
313
+ # ステップごとのループ回数をデクリメント
314
+ global_loop_num -= 1
315
+
316
+ def predict(self, X: Any = None) -> Dict[str, Any]:
317
+ """
318
+ 各ステップを順に適用してデータを予測する。予測を行うためには、最後のステップで
319
+ IteratorMixin でないステップが predict メソッドを持っている必要がある。
320
+
321
+ Args:
322
+ X (Any): 入力データ。
323
+
324
+ Returns:
325
+ Any: 予測結果。
326
+
327
+ Raises:
328
+ RuntimeError: 最後のステップに predict メソッドがない場合。最後のステップで model が作成されていない場合。
329
+ """
330
+
331
+ # y の初期値
332
+ y = None
333
+
334
+ # 全体のglobal_iteratorのループ回数を取得
335
+ global_loop_num = getattr(self.global_iterator, 'loop_num', 1)
336
+
337
+ while global_loop_num > 0:
338
+
339
+ # self.stepsで処理
340
+ for step in self.steps:
341
+ step_name, step_instance = step
342
+
343
+ # 各ステップのループ回数を取得 (IteratorMixinのloop_num)
344
+ step_loop_num = getattr(step_instance, 'loop_num', 1)
345
+
346
+ # 全ステップを step_loop_num 回繰り返す
347
+ while step_loop_num > 0:
348
+
349
+ # Transformer
350
+ X = self._process_step(step, X, y, 'transform')
351
+
352
+ if (
353
+ global_loop_num == 1
354
+ and step_loop_num == 1
355
+ and step_name == self.steps[-1][0]
356
+ ):
357
+
358
+ # Predict
359
+ if hasattr(step_instance, 'predict'):
360
+
361
+ # パラメータをstepと共有(処理前)
362
+ self._assign_global_params(step_instance)
363
+
364
+ # predict 処理
365
+ model = self.models[step_name]
366
+ if model is not None:
367
+ self.results[step_name] = model.predict(X)
368
+
369
+ # パラメータをstepと共有(処理後)
370
+ step_instance.results = self.results
371
+ self._update_params(step_instance)
372
+
373
+ return self.results
374
+
375
+ else:
376
+ # model が見つからなかった場合のエラー
377
+ raise RuntimeError(
378
+ "パイプラインの最後のステップに model が見つかりませんでした。"
379
+ )
380
+
381
+ else:
382
+ # predict メソッドが見つからなかった場合のエラー
383
+ raise RuntimeError(
384
+ "パイプラインの最後のステップに predict メソッドが見つかりませんでした。"
385
+ )
386
+
387
+ else:
388
+ # Predict
389
+ if hasattr(step_instance, 'predict'):
390
+
391
+ # パラメータをstepと共有(処理前)
392
+ self._assign_global_params(step_instance)
393
+
394
+ # predict 処理
395
+ model = self.models[step_name]
396
+ if model is not None:
397
+ self.results[step_name] = model.predict(X)
398
+
399
+ # パラメータをstepと共有(処理後)
400
+ step_instance.results = self.results
401
+ self._update_params(step_instance)
402
+
403
+ # optimize を実行し、結果を y に格納
404
+ if hasattr(step_instance, 'optimize'):
405
+
406
+ # パラメータをstepと共有(処理前)
407
+ self._assign_global_params(step_instance)
408
+
409
+ self.results[step_name] = self._process_step(
410
+ step, X, y, 'optimize'
411
+ )
412
+
413
+ # パラメータをstepと共有(処理後)
414
+ step_instance.results = self.results
415
+ self._update_params(step_instance)
416
+
417
+ # next_params が定義されていれば、次のパラメータを取得
418
+ if hasattr(step_instance, 'next_params'):
419
+
420
+ # パラメータをstepと共有
421
+ self._assign_global_params(step_instance)
422
+
423
+ X, y = step_instance.next_params(X, y)
424
+ self._update_params(step_instance)
425
+
426
+ # ステップごとのループ回数をデクリメント
427
+ step_loop_num -= 1
428
+
429
+ # next_params が定義されていれば、次のパラメータを取得
430
+ if hasattr(self.global_iterator, 'next_params'):
431
+
432
+ # パラメータをstepと共有
433
+ self._assign_global_params(self.global_iterator)
434
+
435
+ X, y = self.global_iterator.next_params(X, y)
436
+ self._update_params(self.global_iterator)
437
+
438
+ # ステップごとのループ回数をデクリメント
439
+ global_loop_num -= 1
440
+
441
+ def get_results(self) -> Dict[str, Any]:
442
+ """
443
+ 最適化結果を取得する。
444
+
445
+ Returns:
446
+ Dict[str, Any]: 各ステップごとの最適化結果。
447
+ """
448
+ return self.results
449
+
450
+ def get_models(self) -> Dict[str, Any]:
451
+ """
452
+ 学習されたモデルを取得する。
453
+
454
+ Returns:
455
+ Dict[str, Any]: 各ステップごとのモデル。
456
+ """
457
+ return self.models
@@ -0,0 +1,5 @@
1
+ # pipeline/steps/__init__.py
2
+
3
+ from .base import BaseStep
4
+ from .optimizer_mixin import OptimizerMixin
5
+ from .iterator_mixin import IteratorMixin
@@ -0,0 +1,27 @@
1
+ from abc import ABC
2
+
3
+
4
+ class BaseStep(ABC):
5
+ def __init__(self):
6
+ self.global_params = {}
7
+ self.local_params = {}
8
+
9
+ def set_global_params(self, params: dict) -> None:
10
+ """
11
+ グローバルパラメータを設定するメソッド。
12
+ デフォルトでは何もしないため、必要なステップだけがオーバーライドする。
13
+
14
+ Args:
15
+ params (dict): グローバルパラメータの辞書。
16
+ """
17
+ self.global_params = params
18
+
19
+ def get_global_params(self) -> dict:
20
+ """
21
+ グローバルパラメータを取得するメソッド。
22
+ デフォルトでは空の辞書を返すため、必要なステップだけがオーバーライドする。
23
+
24
+ Returns:
25
+ dict: グローバルパラメータの辞書。
26
+ """
27
+ return self.global_params
@@ -0,0 +1,31 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, Tuple
3
+ from .base import BaseStep
4
+
5
+
6
+ class IteratorMixin(BaseStep, ABC):
7
+ """
8
+ パイプラインステップ内で使用するイテレータ用のMixinクラス。
9
+ このMixinクラスは次のパラメータセットを生成する `next_params` メソッドの実装を要求します。
10
+ """
11
+
12
+ def __init__(self, loop_num: int = 1) -> None:
13
+ super().__init__()
14
+ self.loop_num = loop_num # デフォルトで1回のループ
15
+ self.models = None
16
+ self.results = None
17
+
18
+ @abstractmethod
19
+ def next_params(self, X: Any, y: Any = None, **iter_params) -> Tuple[Any, Any]:
20
+ """
21
+ 次のパラメータセットを生成する抽象メソッド。
22
+
23
+ Args:
24
+ X (Any): 入力データ。
25
+ y (Any): ターゲットデータ。
26
+ **iter_params: 追加のパラメータ。
27
+
28
+ Returns:
29
+ Tuple[Any, Any]: 次の入力データとターゲットデータ。
30
+ """
31
+ pass
@@ -0,0 +1,42 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any
3
+ from .base import BaseStep
4
+
5
+
6
+ class OptimizerMixin(BaseStep, ABC):
7
+ """
8
+ パイプラインステップ内で使用する最適化処理用のMixinクラス。
9
+ このMixinクラスは、`transform` および `optimize` メソッドをサポートし、`optimize` メソッドの実装を必須とします。
10
+ """
11
+
12
+ def __init__(self) -> None:
13
+ super().__init__()
14
+ self.models = None
15
+ self.results = None
16
+
17
+ def transform(self, X: Any) -> Any:
18
+ """
19
+ オプションの変換メソッド。サブクラスでオーバーライド可能。
20
+
21
+ Args:
22
+ X (Any): 入力データ。
23
+
24
+ Returns:
25
+ Any: 変換後のデータ。
26
+ """
27
+ return X # デフォルトでは変換しない
28
+
29
+ @abstractmethod
30
+ def optimize(self, X: Any = None, y: Any = None, **fit_params) -> Any:
31
+ """
32
+ 抽象的な最適化メソッド。
33
+
34
+ Args:
35
+ X (Any): 入力データ。
36
+ y (Any): ターゲットデータ。
37
+ **fit_params: 追加のパラメータ。
38
+
39
+ Returns:
40
+ Any: 最適化結果。
41
+ """
42
+ pass
@@ -0,0 +1,9 @@
1
+ # qudata/__init__.py
2
+
3
+ # QuData, QuDataInput, QuDataOutput, QuDataBase クラスを外部から直接インポートできるようにする
4
+ from .qudata import QuData
5
+ from .qudata_input import QuDataInput
6
+ from .qudata_output import QuDataOutput
7
+ from .qudata_base import QuDataBase
8
+
9
+ __all__ = ['QuData', 'QuDataInput', 'QuDataOutput', 'QuDataBase']
qudas/qudata/qudata.py ADDED
@@ -0,0 +1,35 @@
1
+ from .qudata_input import QuDataInput
2
+ from .qudata_output import QuDataOutput
3
+ from typing import Optional, Dict, Any
4
+
5
+
6
+ class QuData:
7
+
8
+ @classmethod
9
+ def input(cls, prob: Optional[Dict[str, Any]] = None) -> QuDataInput:
10
+ """
11
+ クラスメソッドとして QuDataInput のインスタンスを作成し、引数を受け取る。
12
+
13
+ Args:
14
+ prob (dict, optional): QuDataInput の引数となる最適化問題データ。
15
+
16
+ Returns:
17
+ QuDataInput のインスタンス。
18
+ """
19
+ return QuDataInput(prob)
20
+
21
+ @classmethod
22
+ def output(
23
+ cls, result: Optional[Dict[str, Any]] = None, result_type: Optional[str] = None
24
+ ) -> QuDataOutput:
25
+ """
26
+ クラスメソッドとして QuDataOutput のインスタンスを作成し、引数を受け取る。
27
+
28
+ Args:
29
+ result (dict, optional): QuDataOutput の引数となる計算結果データ。
30
+ result_type (str, optional): 結果の形式。
31
+
32
+ Returns:
33
+ QuDataOutput のインスタンス。
34
+ """
35
+ return QuDataOutput(result, result_type)
@@ -0,0 +1,30 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Dict, Any
3
+
4
+
5
+ class QuDataBase(ABC):
6
+ def __init__(self, data: Dict[str, Any] = None):
7
+ """
8
+ 初期データを格納する抽象クラス。
9
+
10
+ Args:
11
+ data (dict, optional): 入力または出力データ。デフォルトはNone。
12
+ """
13
+ self.data = {}
14
+
15
+ if data is None:
16
+ self.data = {}
17
+ elif isinstance(data, dict):
18
+ self.data = data
19
+ else:
20
+ raise TypeError(f"{type(data)}は対応していない型です。")
21
+
22
+ # @abstractmethod
23
+ # def from_xxx(self, data):
24
+ # """サブクラスで実装されるべき抽象メソッド"""
25
+ # pass
26
+
27
+ # @abstractmethod
28
+ # def to_xxx(self):
29
+ # """サブクラスで実装されるべき抽象メソッド"""
30
+ # pass