oikan 0.0.3.7__py3-none-any.whl → 0.0.3.9__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.
- oikan/__init__.py +3 -1
- oikan/elasticnet.py +71 -0
- oikan/model.py +43 -20
- {oikan-0.0.3.7.dist-info → oikan-0.0.3.9.dist-info}/METADATA +20 -20
- oikan-0.0.3.9.dist-info/RECORD +11 -0
- oikan-0.0.3.7.dist-info/RECORD +0 -10
- {oikan-0.0.3.7.dist-info → oikan-0.0.3.9.dist-info}/WHEEL +0 -0
- {oikan-0.0.3.7.dist-info → oikan-0.0.3.9.dist-info}/licenses/LICENSE +0 -0
- {oikan-0.0.3.7.dist-info → oikan-0.0.3.9.dist-info}/top_level.txt +0 -0
oikan/__init__.py
CHANGED
@@ -9,6 +9,8 @@ Docs: https://silvermete0r.github.io/oikan/
|
|
9
9
|
'''
|
10
10
|
|
11
11
|
from .model import OIKAN, OIKANClassifier, OIKANRegressor
|
12
|
+
from .neural import TabularNet
|
13
|
+
from .elasticnet import ElasticNet
|
12
14
|
|
13
|
-
__all__ = ['OIKAN', 'OIKANClassifier', 'OIKANRegressor']
|
15
|
+
__all__ = ['OIKAN', 'OIKANClassifier', 'OIKANRegressor', 'TabularNet', 'ElasticNet']
|
14
16
|
__version__ = '0.0.3'
|
oikan/elasticnet.py
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
import torch.nn as nn
|
2
|
+
import torch
|
3
|
+
import numpy as np
|
4
|
+
|
5
|
+
class ElasticNet(nn.Module):
|
6
|
+
def __init__(self, alpha=1.0, l1_ratio=0.5, fit_intercept=False, max_iter=1000, tol=1e-4, random_state=None):
|
7
|
+
super().__init__()
|
8
|
+
self.alpha = alpha
|
9
|
+
self.l1_ratio = l1_ratio
|
10
|
+
self.fit_intercept = fit_intercept
|
11
|
+
self.max_iter = max_iter
|
12
|
+
self.tol = tol
|
13
|
+
self.random_state = random_state
|
14
|
+
self.coef_ = None
|
15
|
+
self.intercept_ = None
|
16
|
+
|
17
|
+
def fit(self, X, y):
|
18
|
+
X = np.asarray(X, dtype=np.float32)
|
19
|
+
y = np.asarray(y, dtype=np.float32)
|
20
|
+
n_samples, n_features = X.shape
|
21
|
+
if y.ndim == 1:
|
22
|
+
y = y.reshape(-1, 1)
|
23
|
+
n_targets = y.shape[1]
|
24
|
+
|
25
|
+
if self.random_state is not None:
|
26
|
+
torch.manual_seed(self.random_state)
|
27
|
+
np.random.seed(self.random_state)
|
28
|
+
|
29
|
+
X_tensor = torch.tensor(X, dtype=torch.float32)
|
30
|
+
y_tensor = torch.tensor(y, dtype=torch.float32)
|
31
|
+
|
32
|
+
W = torch.zeros((n_features, n_targets), requires_grad=True, dtype=torch.float32)
|
33
|
+
if self.fit_intercept:
|
34
|
+
b = torch.zeros(n_targets, requires_grad=True, dtype=torch.float32)
|
35
|
+
else:
|
36
|
+
b = None
|
37
|
+
|
38
|
+
optimizer = torch.optim.Adam([W] + ([b] if b is not None else []), lr=0.05)
|
39
|
+
|
40
|
+
prev_loss = None
|
41
|
+
for _ in range(self.max_iter):
|
42
|
+
optimizer.zero_grad()
|
43
|
+
pred = X_tensor @ W
|
44
|
+
if b is not None:
|
45
|
+
pred = pred + b
|
46
|
+
mse = torch.mean((pred - y_tensor) ** 2)
|
47
|
+
l1 = torch.sum(torch.abs(W))
|
48
|
+
l2 = torch.sum(W ** 2)
|
49
|
+
loss = mse + self.alpha * (self.l1_ratio * l1 + (1 - self.l1_ratio) * l2)
|
50
|
+
loss.backward()
|
51
|
+
optimizer.step()
|
52
|
+
if prev_loss is not None and abs(prev_loss - loss.item()) < self.tol:
|
53
|
+
break
|
54
|
+
prev_loss = loss.item()
|
55
|
+
|
56
|
+
self.coef_ = W.detach().cpu().numpy().T if n_targets > 1 else W.detach().cpu().numpy().flatten()
|
57
|
+
if b is not None:
|
58
|
+
self.intercept_ = b.detach().cpu().numpy()
|
59
|
+
else:
|
60
|
+
self.intercept_ = np.zeros(n_targets) if n_targets > 1 else 0.0
|
61
|
+
return self
|
62
|
+
|
63
|
+
def predict(self, X):
|
64
|
+
X = np.asarray(X, dtype=np.float32)
|
65
|
+
if self.coef_ is None:
|
66
|
+
raise RuntimeError("Model not fitted yet.")
|
67
|
+
W = self.coef_.T if self.coef_.ndim == 2 else self.coef_
|
68
|
+
y_pred = X @ W
|
69
|
+
if self.intercept_ is not None:
|
70
|
+
y_pred += self.intercept_
|
71
|
+
return y_pred
|
oikan/model.py
CHANGED
@@ -3,15 +3,16 @@ import torch
|
|
3
3
|
import torch.nn as nn
|
4
4
|
import torch.optim as optim
|
5
5
|
from sklearn.preprocessing import PolynomialFeatures
|
6
|
-
from sklearn.linear_model import ElasticNet
|
7
6
|
from abc import ABC, abstractmethod
|
8
7
|
import json
|
8
|
+
from .elasticnet import ElasticNet
|
9
9
|
from .neural import TabularNet
|
10
10
|
from .utils import evaluate_basis_functions, get_features_involved, sympify_formula, get_latex_formula
|
11
11
|
from sklearn.model_selection import train_test_split
|
12
12
|
from sklearn.metrics import r2_score, accuracy_score
|
13
13
|
from .exceptions import *
|
14
14
|
import sys
|
15
|
+
from tqdm import tqdm
|
15
16
|
|
16
17
|
class OIKAN(ABC):
|
17
18
|
"""
|
@@ -25,9 +26,12 @@ class OIKAN(ABC):
|
|
25
26
|
Activation function for the neural network ('relu', 'tanh', 'leaky_relu', 'elu', 'swish', 'gelu').
|
26
27
|
augmentation_factor : int, optional (default=10)
|
27
28
|
Number of augmented samples per original sample.
|
28
|
-
alpha : float, optional (default=0
|
29
|
-
|
30
|
-
|
29
|
+
alpha : float, optional (default=1.0)
|
30
|
+
ElasticNet regularization strength.
|
31
|
+
l1_ratio: float, optional (default=0.5)
|
32
|
+
ElasticNet mixing parameter (0 <= l1_ratio <= 1).
|
33
|
+
0 is equivalent to Ridge regression, 1 is equivalent to Lasso.
|
34
|
+
sigma : float, optional (default=5.0)
|
31
35
|
Standard deviation of Gaussian noise for data augmentation.
|
32
36
|
top_k : int, optional (default=5)
|
33
37
|
Number of top features to select in hierarchical symbolic regression.
|
@@ -45,7 +49,7 @@ class OIKAN(ABC):
|
|
45
49
|
Random seed for reproducibility.
|
46
50
|
"""
|
47
51
|
def __init__(self, hidden_sizes=[64, 64], activation='relu', augmentation_factor=10,
|
48
|
-
alpha=0.
|
52
|
+
alpha=1.0, l1_ratio=0.5, sigma=5.0, epochs=100, lr=0.001, batch_size=32,
|
49
53
|
verbose=False, evaluate_nn=False, top_k=5, random_state=None):
|
50
54
|
if not isinstance(hidden_sizes, list) or not all(isinstance(x, int) and x > 0 for x in hidden_sizes):
|
51
55
|
raise InvalidParameterError("hidden_sizes must be a list of positive integers")
|
@@ -63,6 +67,8 @@ class OIKAN(ABC):
|
|
63
67
|
raise InvalidParameterError("epochs must be a positive integer")
|
64
68
|
if not 0 <= alpha <= 1:
|
65
69
|
raise InvalidParameterError("alpha must be between 0 and 1")
|
70
|
+
if not 0 <= l1_ratio <= 1:
|
71
|
+
raise InvalidParameterError("l1_ratio must be between 0 and 1")
|
66
72
|
if sigma <= 0:
|
67
73
|
raise InvalidParameterError("sigma must be positive")
|
68
74
|
|
@@ -70,6 +76,7 @@ class OIKAN(ABC):
|
|
70
76
|
self.activation = activation
|
71
77
|
self.augmentation_factor = augmentation_factor
|
72
78
|
self.alpha = alpha
|
79
|
+
self.l1_ratio = l1_ratio
|
73
80
|
self.sigma = sigma
|
74
81
|
self.epochs = epochs
|
75
82
|
self.lr = lr
|
@@ -353,14 +360,23 @@ class OIKAN(ABC):
|
|
353
360
|
if np.any(np.isinf(X)) or np.any(np.isinf(y)):
|
354
361
|
raise NumericalInstabilityError("Input data contains infinite values")
|
355
362
|
|
356
|
-
|
363
|
+
if self.verbose:
|
364
|
+
print("\nStage 1: Coarse Model Fitting")
|
365
|
+
|
357
366
|
coarse_degree = 2 # Fixed low degree for coarse model
|
358
367
|
poly_coarse = PolynomialFeatures(degree=coarse_degree, include_bias=True)
|
368
|
+
|
369
|
+
if self.verbose:
|
370
|
+
print("Generating polynomial features...")
|
359
371
|
X_poly_coarse = poly_coarse.fit_transform(X)
|
360
|
-
|
372
|
+
|
373
|
+
if self.verbose:
|
374
|
+
print("Fitting coarse elastic net model...")
|
375
|
+
model_coarse = ElasticNet(alpha=self.alpha, l1_ratio=self.l1_ratio, fit_intercept=False, random_state=self.random_state)
|
361
376
|
model_coarse.fit(X_poly_coarse, y)
|
362
377
|
|
363
|
-
|
378
|
+
if self.verbose:
|
379
|
+
print("Computing feature importances...")
|
364
380
|
basis_functions_coarse = poly_coarse.get_feature_names_out()
|
365
381
|
if len(y.shape) == 1 or y.shape[1] == 1:
|
366
382
|
coef_coarse = model_coarse.coef_.flatten()
|
@@ -368,7 +384,7 @@ class OIKAN(ABC):
|
|
368
384
|
coef_coarse = np.sum(np.abs(model_coarse.coef_), axis=0)
|
369
385
|
|
370
386
|
importances = np.zeros(X.shape[1])
|
371
|
-
for i, func in enumerate(basis_functions_coarse):
|
387
|
+
for i, func in enumerate(tqdm(basis_functions_coarse, disable=not self.verbose, desc="Analyzing features")):
|
372
388
|
features_involved = get_features_involved(func)
|
373
389
|
for idx in features_involved:
|
374
390
|
importances[idx] += np.abs(coef_coarse[i])
|
@@ -379,11 +395,13 @@ class OIKAN(ABC):
|
|
379
395
|
# Select top K features
|
380
396
|
top_k_indices = np.argsort(importances)[::-1][:self.top_k]
|
381
397
|
|
382
|
-
|
383
|
-
|
398
|
+
if self.verbose:
|
399
|
+
print(f"\nStage 2: Refined Model with top {self.top_k} features")
|
400
|
+
print("Generating additional non-linear features...")
|
401
|
+
|
384
402
|
additional_features = []
|
385
403
|
additional_names = []
|
386
|
-
for i in top_k_indices:
|
404
|
+
for i in tqdm(top_k_indices, disable=not self.verbose, desc="Generating features"):
|
387
405
|
# Higher-degree polynomial
|
388
406
|
additional_features.append(X[:, i]**3)
|
389
407
|
additional_names.append(f'x{i}^3')
|
@@ -395,15 +413,18 @@ class OIKAN(ABC):
|
|
395
413
|
additional_features.append(np.sin(X[:, i]))
|
396
414
|
additional_names.append(f'sin_x{i}')
|
397
415
|
|
398
|
-
|
416
|
+
if self.verbose:
|
417
|
+
print("Combining features and fitting final model...")
|
399
418
|
X_additional = np.column_stack(additional_features)
|
400
419
|
X_refined = np.hstack([X_poly_coarse, X_additional])
|
401
420
|
basis_functions_refined = list(basis_functions_coarse) + additional_names
|
402
421
|
|
403
|
-
|
404
|
-
model_refined = ElasticNet(alpha=self.alpha, fit_intercept=False)
|
422
|
+
model_refined = ElasticNet(alpha=self.alpha, l1_ratio=self.l1_ratio, fit_intercept=False, random_state=self.random_state)
|
405
423
|
model_refined.fit(X_refined, y)
|
406
424
|
|
425
|
+
if self.verbose:
|
426
|
+
print("Building final symbolic model...")
|
427
|
+
|
407
428
|
# Store symbolic model
|
408
429
|
if len(y.shape) == 1 or y.shape[1] == 1:
|
409
430
|
# Regression
|
@@ -418,7 +439,7 @@ class OIKAN(ABC):
|
|
418
439
|
# Classification
|
419
440
|
coefficients_list = []
|
420
441
|
selected_indices = set()
|
421
|
-
for c in range(y.shape[1]):
|
442
|
+
for c in tqdm(range(y.shape[1]), disable=not self.verbose, desc="Processing classes"):
|
422
443
|
coef = model_refined.coef_[c]
|
423
444
|
indices = np.where(np.abs(coef) > 1e-6)[0]
|
424
445
|
selected_indices.update(indices)
|
@@ -454,7 +475,7 @@ class OIKANRegressor(OIKAN):
|
|
454
475
|
self._train_neural_net(X, y, output_size=1, loss_fn=nn.MSELoss())
|
455
476
|
|
456
477
|
if self.verbose:
|
457
|
-
print(f"Original data: features shape: {X.shape} | target shape: {y.shape}")
|
478
|
+
print(f"Original data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
458
479
|
|
459
480
|
X_aug = self._generate_augmented_data(X)
|
460
481
|
|
@@ -463,13 +484,14 @@ class OIKANRegressor(OIKAN):
|
|
463
484
|
y_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
|
464
485
|
|
465
486
|
if self.verbose:
|
466
|
-
print(f"Augmented data: features shape: {X_aug.shape} | target shape: {y_aug.shape}")
|
487
|
+
print(f"Augmented data: features shape: {X_aug.shape} | target shape: {y_aug.shape} | size: {X_aug.nbytes / (1024 * 1024):.2f} MB")
|
467
488
|
|
468
489
|
X_combined = np.vstack([X, X_aug])
|
469
490
|
y_combined = np.vstack([y, y_aug])
|
470
491
|
else:
|
471
492
|
if self.verbose:
|
472
493
|
print("Skipping neural network training (augmentation_factor=1)")
|
494
|
+
print(f"Data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
473
495
|
X_combined = X
|
474
496
|
y_combined = y
|
475
497
|
|
@@ -523,7 +545,7 @@ class OIKANClassifier(OIKAN):
|
|
523
545
|
self._train_neural_net(X, y_onehot, output_size=n_classes, loss_fn=nn.CrossEntropyLoss())
|
524
546
|
|
525
547
|
if self.verbose:
|
526
|
-
print(f"Original data: features shape: {X.shape} | target shape: {y.shape}")
|
548
|
+
print(f"Original data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
527
549
|
|
528
550
|
X_aug = self._generate_augmented_data(X)
|
529
551
|
|
@@ -532,13 +554,14 @@ class OIKANClassifier(OIKAN):
|
|
532
554
|
logits_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
|
533
555
|
|
534
556
|
if self.verbose:
|
535
|
-
print(f"Augmented data: features shape: {X_aug.shape} | target shape: {logits_aug.shape}")
|
557
|
+
print(f"Augmented data: features shape: {X_aug.shape} | target shape: {logits_aug.shape} | size: {X_aug.nbytes / (1024 * 1024):.2f} MB")
|
536
558
|
|
537
559
|
X_combined = np.vstack([X, X_aug])
|
538
560
|
y_combined = np.vstack([y_onehot.numpy(), logits_aug])
|
539
561
|
else:
|
540
562
|
if self.verbose:
|
541
563
|
print("Skipping neural network training (augmentation_factor=1)")
|
564
|
+
print(f"Data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
542
565
|
X_combined = X
|
543
566
|
y_combined = y_onehot.numpy()
|
544
567
|
|
@@ -1,9 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: oikan
|
3
|
-
Version: 0.0.3.
|
3
|
+
Version: 0.0.3.9
|
4
4
|
Summary: OIKAN: Neuro-Symbolic ML for Scientific Discovery
|
5
5
|
Author: Arman Zhalgasbayev
|
6
6
|
License: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/silvermete0r/oikan
|
8
|
+
Project-URL: Bug Tracker, https://github.com/silvermete0r/oikan/issues
|
7
9
|
Classifier: Programming Language :: Python :: 3
|
8
10
|
Classifier: License :: OSI Approved :: MIT License
|
9
11
|
Classifier: Operating System :: OS Independent
|
@@ -49,19 +51,9 @@ OIKAN is a neuro-symbolic machine learning framework inspired by Kolmogorov-Arno
|
|
49
51
|
- 🔬 **Research-Focused**: Designed for academic exploration and experimentation
|
50
52
|
- 📈 **Multi-Task**: Supports both regression and classification problems
|
51
53
|
|
52
|
-
##
|
54
|
+
## Key Aspects
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
1. **Theoretical Foundation**: The Kolmogorov-Arnold theorem states that any continuous n-dimensional function can be decomposed into a combination of single-variable functions:
|
57
|
-
|
58
|
-
```
|
59
|
-
f(x₁,...,xₙ) = ∑(j=0 to 2n){ φⱼ( ∑(i=1 to n) ψᵢⱼ(xᵢ) ) }
|
60
|
-
```
|
61
|
-
|
62
|
-
where φⱼ and ψᵢⱼ are continuous univariate functions.
|
63
|
-
|
64
|
-
2. **Neural Implementation**: OIKAN uses a specialized architecture combining:
|
56
|
+
1. **Neural Implementation**: OIKAN uses a specialized architecture combining:
|
65
57
|
- Feature transformation layers with interpretable basis functions
|
66
58
|
- Symbolic regression for formula extraction (ElasticNet-based)
|
67
59
|
- Automatic pruning of insignificant terms
|
@@ -78,7 +70,7 @@ OIKAN implements a modern interpretation of the Kolmogorov-Arnold Representation
|
|
78
70
|
self.symbolic_regression = SymbolicRegression(alpha=alpha)
|
79
71
|
```
|
80
72
|
|
81
|
-
|
73
|
+
2. **Basis Functions**: Core set of interpretable transformations:
|
82
74
|
```python
|
83
75
|
SYMBOLIC_FUNCTIONS = {
|
84
76
|
'linear': 'x', # Direct relationships
|
@@ -92,10 +84,10 @@ OIKAN implements a modern interpretation of the Kolmogorov-Arnold Representation
|
|
92
84
|
}
|
93
85
|
```
|
94
86
|
|
95
|
-
|
87
|
+
3. **Formula Extraction Process**:
|
96
88
|
- Train neural network on raw data
|
97
89
|
- Generate augmented samples for better coverage
|
98
|
-
- Perform
|
90
|
+
- Perform ElasticNet-regularization
|
99
91
|
- Prune terms with coefficients below threshold
|
100
92
|
- Export human-readable mathematical expressions
|
101
93
|
|
@@ -127,6 +119,9 @@ pip install -e . # Install in development mode
|
|
127
119
|
| Dependencies | torch, numpy, scikit-learn, sympy, tqdm |
|
128
120
|
|
129
121
|
### Regression Example
|
122
|
+
|
123
|
+
> **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as Elastic Net assumes that the model intercept has already been accounted for.
|
124
|
+
|
130
125
|
```python
|
131
126
|
from oikan import OIKANRegressor
|
132
127
|
from sklearn.metrics import mean_squared_error
|
@@ -136,8 +131,9 @@ model = OIKANRegressor(
|
|
136
131
|
hidden_sizes=[32, 32], # Hidden layer sizes
|
137
132
|
activation='relu', # Activation function (other options: 'tanh', 'leaky_relu', 'elu', 'swish', 'gelu')
|
138
133
|
augmentation_factor=5, # Augmentation factor for data generation
|
139
|
-
alpha=0
|
140
|
-
|
134
|
+
alpha=1.0, # ElasticNet regularization strength (Symbolic regression)
|
135
|
+
l1_rate=0.5, # ElasticNet mixing parameter (0 <= l1_ratio <= 1). 0 is equivalent to Ridge regression, 1 is equivalent to Lasso (Symbolic regression)
|
136
|
+
sigma=5, # Standard deviation of Gaussian noise for data augmentation
|
141
137
|
top_k=5, # Number of top features to select (Symbolic regression)
|
142
138
|
epochs=100, # Number of training epochs
|
143
139
|
lr=0.001, # Learning rate
|
@@ -177,6 +173,9 @@ loaded_model.load("outputs/model.json")
|
|
177
173
|
|
178
174
|
|
179
175
|
### Classification Example
|
176
|
+
|
177
|
+
> **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as Elastic Net assumes that the model intercept has already been accounted for.
|
178
|
+
|
180
179
|
```python
|
181
180
|
from oikan import OIKANClassifier
|
182
181
|
from sklearn.metrics import accuracy_score
|
@@ -186,8 +185,9 @@ model = OIKANClassifier(
|
|
186
185
|
hidden_sizes=[32, 32], # Hidden layer sizes
|
187
186
|
activation='relu', # Activation function (other options: 'tanh', 'leaky_relu', 'elu', 'swish', 'gelu')
|
188
187
|
augmentation_factor=10, # Augmentation factor for data generation
|
189
|
-
alpha=0
|
190
|
-
|
188
|
+
alpha=1.0, # ElasticNet regularization strength (Symbolic regression)
|
189
|
+
l1_rate=0.5, # ElasticNet mixing parameter (0 <= l1_ratio <= 1). 0 is equivalent to Ridge regression, 1 is equivalent to Lasso (Symbolic regression)
|
190
|
+
sigma=5, # Standard deviation of Gaussian noise for data augmentation
|
191
191
|
top_k=5, # Number of top features to select (Symbolic regression)
|
192
192
|
epochs=100, # # Number of training epochs
|
193
193
|
lr=0.001, # Learning rate
|
@@ -0,0 +1,11 @@
|
|
1
|
+
oikan/__init__.py,sha256=Dh1Rf9ONRdm75B6tFiv9Y9P6NNiHAiKPCGDMuag6TTE,724
|
2
|
+
oikan/elasticnet.py,sha256=yByuG9KCFQ4PpT2ze6oTSDy0DxvdF5MAJoegUGEipSA,2614
|
3
|
+
oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
|
4
|
+
oikan/model.py,sha256=UAjRYwb-kEap4AJkJ3OVmpNWpun0qgcad5m6x-mUbN8,26237
|
5
|
+
oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
|
6
|
+
oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
|
7
|
+
oikan-0.0.3.9.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
|
8
|
+
oikan-0.0.3.9.dist-info/METADATA,sha256=KCUIcXDdneq4MTgnIKmOHf0OPjWUzmQSm21ayOIYQZs,13124
|
9
|
+
oikan-0.0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
10
|
+
oikan-0.0.3.9.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
|
11
|
+
oikan-0.0.3.9.dist-info/RECORD,,
|
oikan-0.0.3.7.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
oikan/__init__.py,sha256=zEzhm1GYLT4vNaIQ4CgZcNpUk3uo8SWnoaHYtHW_XSQ,628
|
2
|
-
oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
|
3
|
-
oikan/model.py,sha256=TC2-R00GOjFb7ePzKTqeYkOiVlqUK7KP0mXsnJhg9ik,24736
|
4
|
-
oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
|
5
|
-
oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
|
6
|
-
oikan-0.0.3.7.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
|
7
|
-
oikan-0.0.3.7.dist-info/METADATA,sha256=nrel6O7TXdbtJHSNCzvqPq_IELeQWx0azfrU4Jq6sps,12749
|
8
|
-
oikan-0.0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
9
|
-
oikan-0.0.3.7.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
|
10
|
-
oikan-0.0.3.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|