oikan 0.0.3.6__py3-none-any.whl → 0.0.3.8__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/model.py CHANGED
@@ -12,6 +12,7 @@ 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
  """
@@ -319,11 +320,15 @@ class OIKAN(ABC):
319
320
 
320
321
  def _generate_augmented_data(self, X):
321
322
  """Generates augmented data by adding Gaussian noise."""
323
+ if self.augmentation_factor == 1:
324
+ return np.array([]).reshape(0, X.shape[1])
325
+
322
326
  X_aug = []
323
- for _ in range(self.augmentation_factor):
327
+ for _ in range(self.augmentation_factor - 1):
324
328
  noise = np.random.normal(0, self.sigma, X.shape)
325
329
  X_perturbed = X + noise
326
330
  X_aug.append(X_perturbed)
331
+
327
332
  return np.vstack(X_aug)
328
333
 
329
334
  def _perform_symbolic_regression(self, X, y):
@@ -349,14 +354,23 @@ class OIKAN(ABC):
349
354
  if np.any(np.isinf(X)) or np.any(np.isinf(y)):
350
355
  raise NumericalInstabilityError("Input data contains infinite values")
351
356
 
352
- # Stage 1: Coarse Model
357
+ if self.verbose:
358
+ print("\nStage 1: Coarse Model Fitting")
359
+
353
360
  coarse_degree = 2 # Fixed low degree for coarse model
354
361
  poly_coarse = PolynomialFeatures(degree=coarse_degree, include_bias=True)
362
+
363
+ if self.verbose:
364
+ print("Generating polynomial features...")
355
365
  X_poly_coarse = poly_coarse.fit_transform(X)
366
+
367
+ if self.verbose:
368
+ print("Fitting coarse elastic net model...")
356
369
  model_coarse = ElasticNet(alpha=self.alpha, fit_intercept=False)
357
370
  model_coarse.fit(X_poly_coarse, y)
358
371
 
359
- # Compute feature importances for original features
372
+ if self.verbose:
373
+ print("Computing feature importances...")
360
374
  basis_functions_coarse = poly_coarse.get_feature_names_out()
361
375
  if len(y.shape) == 1 or y.shape[1] == 1:
362
376
  coef_coarse = model_coarse.coef_.flatten()
@@ -364,7 +378,7 @@ class OIKAN(ABC):
364
378
  coef_coarse = np.sum(np.abs(model_coarse.coef_), axis=0)
365
379
 
366
380
  importances = np.zeros(X.shape[1])
367
- for i, func in enumerate(basis_functions_coarse):
381
+ for i, func in enumerate(tqdm(basis_functions_coarse, disable=not self.verbose, desc="Analyzing features")):
368
382
  features_involved = get_features_involved(func)
369
383
  for idx in features_involved:
370
384
  importances[idx] += np.abs(coef_coarse[i])
@@ -375,11 +389,13 @@ class OIKAN(ABC):
375
389
  # Select top K features
376
390
  top_k_indices = np.argsort(importances)[::-1][:self.top_k]
377
391
 
378
- # Stage 2: Refined Model
379
- # ~ generate additional non-linear features for top K features
392
+ if self.verbose:
393
+ print(f"\nStage 2: Refined Model with top {self.top_k} features")
394
+ print("Generating additional non-linear features...")
395
+
380
396
  additional_features = []
381
397
  additional_names = []
382
- for i in top_k_indices:
398
+ for i in tqdm(top_k_indices, disable=not self.verbose, desc="Generating features"):
383
399
  # Higher-degree polynomial
384
400
  additional_features.append(X[:, i]**3)
385
401
  additional_names.append(f'x{i}^3')
@@ -391,15 +407,18 @@ class OIKAN(ABC):
391
407
  additional_features.append(np.sin(X[:, i]))
392
408
  additional_names.append(f'sin_x{i}')
393
409
 
394
- # Combine features
410
+ if self.verbose:
411
+ print("Combining features and fitting final model...")
395
412
  X_additional = np.column_stack(additional_features)
396
413
  X_refined = np.hstack([X_poly_coarse, X_additional])
397
414
  basis_functions_refined = list(basis_functions_coarse) + additional_names
398
415
 
399
- # Fit refined model
400
416
  model_refined = ElasticNet(alpha=self.alpha, fit_intercept=False)
401
417
  model_refined.fit(X_refined, y)
402
418
 
419
+ if self.verbose:
420
+ print("Building final symbolic model...")
421
+
403
422
  # Store symbolic model
404
423
  if len(y.shape) == 1 or y.shape[1] == 1:
405
424
  # Regression
@@ -414,7 +433,7 @@ class OIKAN(ABC):
414
433
  # Classification
415
434
  coefficients_list = []
416
435
  selected_indices = set()
417
- for c in range(y.shape[1]):
436
+ for c in tqdm(range(y.shape[1]), disable=not self.verbose, desc="Processing classes"):
418
437
  coef = model_refined.coef_[c]
419
438
  indices = np.where(np.abs(coef) > 1e-6)[0]
420
439
  selected_indices.update(indices)
@@ -445,16 +464,32 @@ class OIKANRegressor(OIKAN):
445
464
  """
446
465
  X = np.asarray(X)
447
466
  y = np.asarray(y).reshape(-1, 1)
448
- self._train_neural_net(X, y, output_size=1, loss_fn=nn.MSELoss())
449
- if self.verbose:
450
- print(f"Original data: features shape: {X.shape} | target shape: {y.shape}")
451
- X_aug = self._generate_augmented_data(X)
452
- self.neural_net.eval()
453
- with torch.no_grad():
454
- y_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
455
- if self.verbose:
456
- print(f"Augmented data: features shape: {X_aug.shape} | target shape: {y_aug.shape}")
457
- self._perform_symbolic_regression(X_aug, y_aug)
467
+
468
+ if self.augmentation_factor > 1:
469
+ self._train_neural_net(X, y, output_size=1, loss_fn=nn.MSELoss())
470
+
471
+ if self.verbose:
472
+ print(f"Original data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
473
+
474
+ X_aug = self._generate_augmented_data(X)
475
+
476
+ self.neural_net.eval()
477
+ with torch.no_grad():
478
+ y_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
479
+
480
+ if self.verbose:
481
+ print(f"Augmented data: features shape: {X_aug.shape} | target shape: {y_aug.shape} | size: {X_aug.nbytes / (1024 * 1024):.2f} MB")
482
+
483
+ X_combined = np.vstack([X, X_aug])
484
+ y_combined = np.vstack([y, y_aug])
485
+ else:
486
+ if self.verbose:
487
+ print("Skipping neural network training (augmentation_factor=1)")
488
+ print(f"Data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
489
+ X_combined = X
490
+ y_combined = y
491
+
492
+ self._perform_symbolic_regression(X_combined, y_combined)
458
493
  if self.verbose:
459
494
  print("OIKANRegressor model training completed successfully!")
460
495
 
@@ -499,16 +534,32 @@ class OIKANClassifier(OIKAN):
499
534
  self.classes_ = le.classes_
500
535
  n_classes = len(self.classes_)
501
536
  y_onehot = nn.functional.one_hot(torch.tensor(y_encoded), num_classes=n_classes).float()
502
- self._train_neural_net(X, y_onehot, output_size=n_classes, loss_fn=nn.CrossEntropyLoss())
503
- if self.verbose:
504
- print(f"Original data: features shape: {X.shape} | target shape: {y.shape}")
505
- X_aug = self._generate_augmented_data(X)
506
- self.neural_net.eval()
507
- with torch.no_grad():
508
- logits_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
509
- if self.verbose:
510
- print(f"Augmented data: features shape: {X_aug.shape} | target shape: {logits_aug.shape}")
511
- self._perform_symbolic_regression(X_aug, logits_aug)
537
+
538
+ if self.augmentation_factor > 1:
539
+ self._train_neural_net(X, y_onehot, output_size=n_classes, loss_fn=nn.CrossEntropyLoss())
540
+
541
+ if self.verbose:
542
+ print(f"Original data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
543
+
544
+ X_aug = self._generate_augmented_data(X)
545
+
546
+ self.neural_net.eval()
547
+ with torch.no_grad():
548
+ logits_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
549
+
550
+ if self.verbose:
551
+ print(f"Augmented data: features shape: {X_aug.shape} | target shape: {logits_aug.shape} | size: {X_aug.nbytes / (1024 * 1024):.2f} MB")
552
+
553
+ X_combined = np.vstack([X, X_aug])
554
+ y_combined = np.vstack([y_onehot.numpy(), logits_aug])
555
+ else:
556
+ if self.verbose:
557
+ print("Skipping neural network training (augmentation_factor=1)")
558
+ print(f"Data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
559
+ X_combined = X
560
+ y_combined = y_onehot.numpy()
561
+
562
+ self._perform_symbolic_regression(X_combined, y_combined)
512
563
  if self.verbose:
513
564
  print("OIKANClassifier model training completed successfully!")
514
565
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oikan
3
- Version: 0.0.3.6
3
+ Version: 0.0.3.8
4
4
  Summary: OIKAN: Neuro-Symbolic ML for Scientific Discovery
5
5
  Author: Arman Zhalgasbayev
6
6
  License: MIT
@@ -0,0 +1,10 @@
1
+ oikan/__init__.py,sha256=zEzhm1GYLT4vNaIQ4CgZcNpUk3uo8SWnoaHYtHW_XSQ,628
2
+ oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
3
+ oikan/model.py,sha256=K-cBAUvfw3B8wxWjNSUC1CadU1iVUb8erapUpD9KzKw,25822
4
+ oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
5
+ oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
6
+ oikan-0.0.3.8.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
7
+ oikan-0.0.3.8.dist-info/METADATA,sha256=jmDvzPj-d_JH4yAZiBf45-mjItUVRepX1Xv2cMqqAkA,12749
8
+ oikan-0.0.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ oikan-0.0.3.8.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
10
+ oikan-0.0.3.8.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- oikan/__init__.py,sha256=zEzhm1GYLT4vNaIQ4CgZcNpUk3uo8SWnoaHYtHW_XSQ,628
2
- oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
3
- oikan/model.py,sha256=vnn5THWhndj5-P2Vsa78CErsT24LVmjMd8CnWeW09Kg,23663
4
- oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
5
- oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
6
- oikan-0.0.3.6.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
7
- oikan-0.0.3.6.dist-info/METADATA,sha256=P-07jTsmYsaANnQOjh_mzmjLk1Q9rqN665CBp_FKYjU,12749
8
- oikan-0.0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- oikan-0.0.3.6.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
10
- oikan-0.0.3.6.dist-info/RECORD,,