oikan 0.0.3.9__py3-none-any.whl → 0.0.3.11__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/elasticnet.py CHANGED
@@ -3,7 +3,7 @@ import torch
3
3
  import numpy as np
4
4
 
5
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):
6
+ def __init__(self, alpha=1.0, l1_ratio=0.5, fit_intercept=False, max_iter=5000, tol=1e-4, random_state=None):
7
7
  super().__init__()
8
8
  self.alpha = alpha
9
9
  self.l1_ratio = l1_ratio
oikan/model.py CHANGED
@@ -2,7 +2,6 @@ import numpy as np
2
2
  import torch
3
3
  import torch.nn as nn
4
4
  import torch.optim as optim
5
- from sklearn.preprocessing import PolynomialFeatures
6
5
  from abc import ABC, abstractmethod
7
6
  import json
8
7
  from .elasticnet import ElasticNet
@@ -88,6 +87,7 @@ class OIKAN(ABC):
88
87
  self.symbolic_model = None
89
88
  self.evaluation_done = False
90
89
  self.random_state = random_state
90
+ self.__version__ = '0.0.3'
91
91
 
92
92
  if self.random_state is not None:
93
93
  torch.manual_seed(self.random_state)
@@ -300,8 +300,10 @@ class OIKAN(ABC):
300
300
  if self.neural_net is None:
301
301
  self.neural_net = TabularNet(input_size, self.hidden_sizes, output_size, self.activation)
302
302
  optimizer = optim.Adam(self.neural_net.parameters(), lr=self.lr)
303
- dataset = torch.utils.data.TensorDataset(torch.tensor(X, dtype=torch.float32),
304
- torch.tensor(y, dtype=torch.float32))
303
+ dataset = torch.utils.data.TensorDataset(
304
+ torch.tensor(X, dtype=torch.float32),
305
+ torch.tensor(y, dtype=torch.float32)
306
+ )
305
307
  loader = torch.utils.data.DataLoader(dataset, batch_size=self.batch_size, shuffle=True)
306
308
  self.neural_net.train()
307
309
 
@@ -362,14 +364,32 @@ class OIKAN(ABC):
362
364
 
363
365
  if self.verbose:
364
366
  print("\nStage 1: Coarse Model Fitting")
365
-
366
- coarse_degree = 2 # Fixed low degree for coarse model
367
- poly_coarse = PolynomialFeatures(degree=coarse_degree, include_bias=True)
368
367
 
368
+ # Generate polynomial features
369
369
  if self.verbose:
370
370
  print("Generating polynomial features...")
371
- X_poly_coarse = poly_coarse.fit_transform(X)
372
-
371
+ n_samples, n_features = X.shape
372
+
373
+ bias = np.ones((n_samples, 1))
374
+ features = X
375
+ powers_of_2 = X ** 2
376
+
377
+ X_poly_coarse = np.hstack([bias, features, powers_of_2])
378
+ basis_functions_coarse = ['1'] + [f'x{i}' for i in range(n_features)] + [f'x{i}^2' for i in range(n_features)]
379
+
380
+ # Generate random interaction features (O(N^2) -> O(N))
381
+ if self.verbose:
382
+ print("Generating random interaction features...")
383
+ rng = np.random.default_rng(self.random_state)
384
+ random_pairs = rng.choice(n_features, size=(n_features // 2, 2), replace=False)
385
+ interaction_features = np.array([X[:, i] * X[:, j] for i, j in random_pairs]).T
386
+ interaction_feature_names = [f"x{i} x{j}" for i, j in random_pairs]
387
+
388
+ # Combine all features
389
+ X_poly_coarse = np.hstack([X_poly_coarse, interaction_features])
390
+ basis_functions_coarse.extend(interaction_feature_names)
391
+
392
+ # Fit coarse elastic net model
373
393
  if self.verbose:
374
394
  print("Fitting coarse elastic net model...")
375
395
  model_coarse = ElasticNet(alpha=self.alpha, l1_ratio=self.l1_ratio, fit_intercept=False, random_state=self.random_state)
@@ -377,7 +397,7 @@ class OIKAN(ABC):
377
397
 
378
398
  if self.verbose:
379
399
  print("Computing feature importances...")
380
- basis_functions_coarse = poly_coarse.get_feature_names_out()
400
+
381
401
  if len(y.shape) == 1 or y.shape[1] == 1:
382
402
  coef_coarse = model_coarse.coef_.flatten()
383
403
  else:
@@ -443,7 +463,7 @@ class OIKAN(ABC):
443
463
  coef = model_refined.coef_[c]
444
464
  indices = np.where(np.abs(coef) > 1e-6)[0]
445
465
  selected_indices.update(indices)
446
- selected_indices = list(selected_indices)
466
+ selected_indices = [i for i in selected_indices if i < len(basis_functions_refined)]
447
467
  basis_functions = [basis_functions_refined[i] for i in selected_indices]
448
468
  for c in range(y.shape[1]):
449
469
  coef = model_refined.coef_[c]
@@ -454,6 +474,22 @@ class OIKAN(ABC):
454
474
  'basis_functions': basis_functions,
455
475
  'coefficients_list': coefficients_list
456
476
  }
477
+
478
+ def _print_system_info(self):
479
+ """Prints system information (for debugging purposes)."""
480
+ import platform
481
+ import os
482
+ print("\n" + "="*30)
483
+ print("System Information:")
484
+ print(f"OIKAN version: {self.__version__}")
485
+ print(f"Python version: {platform.python_version()}")
486
+ print(f"NumPy version: {np.__version__}")
487
+ print(f"Torch version: {torch.__version__}")
488
+ print(f"Device: {'CUDA' if torch.cuda.is_available() else 'CPU'}")
489
+ print(f"Number of CPU cores: {os.cpu_count()}")
490
+ print(f"Memory Usage: {torch.cuda.memory_allocated() / (1024 ** 2) if torch.cuda.is_available() else 'N/A'} MB")
491
+ print(f"Architecture: {platform.machine()}")
492
+ print("="*30 + "\n")
457
493
 
458
494
  class OIKANRegressor(OIKAN):
459
495
  """OIKAN model for regression tasks."""
@@ -468,6 +504,9 @@ class OIKANRegressor(OIKAN):
468
504
  y : array-like of shape (n_samples,)
469
505
  Target values.
470
506
  """
507
+ if self.verbose:
508
+ self._print_system_info()
509
+
471
510
  X = np.asarray(X)
472
511
  y = np.asarray(y).reshape(-1, 1)
473
512
 
@@ -533,6 +572,9 @@ class OIKANClassifier(OIKAN):
533
572
  y : array-like of shape (n_samples,)
534
573
  Target labels.
535
574
  """
575
+ if self.verbose:
576
+ self._print_system_info()
577
+
536
578
  X = np.asarray(X)
537
579
  from sklearn.preprocessing import LabelEncoder
538
580
  le = LabelEncoder()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oikan
3
- Version: 0.0.3.9
3
+ Version: 0.0.3.11
4
4
  Summary: OIKAN: Neuro-Symbolic ML for Scientific Discovery
5
5
  Author: Arman Zhalgasbayev
6
6
  License: MIT
@@ -67,7 +67,7 @@ OIKAN is a neuro-symbolic machine learning framework inspired by Kolmogorov-Arno
67
67
  # Data augmentation for better coverage
68
68
  self.augmented_data = self.augment_data(X, y, augmentation_factor=5)
69
69
  # Symbolic regression for interpretable formulas
70
- self.symbolic_regression = SymbolicRegression(alpha=alpha)
70
+ self.symbolic_regression = SymbolicRegression(alpha=alpha, l1_ratio=0.5)
71
71
  ```
72
72
 
73
73
  2. **Basis Functions**: Core set of interpretable transformations:
@@ -120,7 +120,7 @@ pip install -e . # Install in development mode
120
120
 
121
121
  ### Regression Example
122
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.
123
+ > **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as ElasticNet assumes that the model intercept has already been accounted for.
124
124
 
125
125
  ```python
126
126
  from oikan import OIKANRegressor
@@ -132,7 +132,7 @@ model = OIKANRegressor(
132
132
  activation='relu', # Activation function (other options: 'tanh', 'leaky_relu', 'elu', 'swish', 'gelu')
133
133
  augmentation_factor=5, # Augmentation factor for data generation
134
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)
135
+ l1_ratio=0.5, # ElasticNet mixing parameter (0 <= l1_ratio <= 1). 0 is equivalent to Ridge regression, 1 is equivalent to Lasso (Symbolic regression)
136
136
  sigma=5, # Standard deviation of Gaussian noise for data augmentation
137
137
  top_k=5, # Number of top features to select (Symbolic regression)
138
138
  epochs=100, # Number of training epochs
@@ -174,7 +174,7 @@ loaded_model.load("outputs/model.json")
174
174
 
175
175
  ### Classification Example
176
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.
177
+ > **Suggestion:** Please ensure that the data is normalized using standard scaling (or another suitable normalization method), as ElasticNet assumes that the model intercept has already been accounted for.
178
178
 
179
179
  ```python
180
180
  from oikan import OIKANClassifier
@@ -186,7 +186,7 @@ model = OIKANClassifier(
186
186
  activation='relu', # Activation function (other options: 'tanh', 'leaky_relu', 'elu', 'swish', 'gelu')
187
187
  augmentation_factor=10, # Augmentation factor for data generation
188
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)
189
+ l1_ratio=0.5, # ElasticNet mixing parameter (0 <= l1_ratio <= 1). 0 is equivalent to Ridge regression, 1 is equivalent to Lasso (Symbolic regression)
190
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
@@ -0,0 +1,11 @@
1
+ oikan/__init__.py,sha256=Dh1Rf9ONRdm75B6tFiv9Y9P6NNiHAiKPCGDMuag6TTE,724
2
+ oikan/elasticnet.py,sha256=eeuK4lJ-7lsGZIyiXNH6NKYxhbbKbPp1kp8vLe4t7_4,2614
3
+ oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
4
+ oikan/model.py,sha256=ushOC7UGJWCy5VSkRUmtIBYN8SrXi9nlPW0lwP0ys-s,27937
5
+ oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
6
+ oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
7
+ oikan-0.0.3.11.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
8
+ oikan-0.0.3.11.dist-info/METADATA,sha256=zMlMldKLUmYTv4UZclU9q4eLoLZi4yIwidlk2GK64xs,13139
9
+ oikan-0.0.3.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ oikan-0.0.3.11.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
11
+ oikan-0.0.3.11.dist-info/RECORD,,
@@ -1,11 +0,0 @@
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,,