tgraphx 1.3.2__tar.gz → 1.3.4__tar.gz

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.
Files changed (386) hide show
  1. {tgraphx-1.3.2/tgraphx.egg-info → tgraphx-1.3.4}/PKG-INFO +1 -1
  2. {tgraphx-1.3.2 → tgraphx-1.3.4}/pyproject.toml +1 -1
  3. tgraphx-1.3.4/tests/test_colab_regressions_v134.py +417 -0
  4. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_notebooks_v130.py +24 -5
  5. tgraphx-1.3.4/tests/test_reproducibility_easy_v133.py +137 -0
  6. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/__init__.py +1 -1
  7. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/benchmarks/__init__.py +10 -2
  8. tgraphx-1.3.4/tgraphx/benchmarks/run_v13_benchmark_suite.py +51 -0
  9. tgraphx-1.3.4/tgraphx/benchmarks/suite.py +290 -0
  10. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_workflows.py +6 -2
  11. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/__init__.py +113 -0
  12. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/kernels.py +34 -0
  13. {tgraphx-1.3.2 → tgraphx-1.3.4/tgraphx.egg-info}/PKG-INFO +1 -1
  14. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx.egg-info/SOURCES.txt +4 -0
  15. {tgraphx-1.3.2 → tgraphx-1.3.4}/LICENSE +0 -0
  16. {tgraphx-1.3.2 → tgraphx-1.3.4}/README.md +0 -0
  17. {tgraphx-1.3.2 → tgraphx-1.3.4}/setup.cfg +0 -0
  18. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_3d_support.py +0 -0
  19. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_algorithms.py +0 -0
  20. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_amp_compile.py +0 -0
  21. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_api_stability_labels.py +0 -0
  22. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_backward_compatibility.py +0 -0
  23. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_benchmark_smoke.py +0 -0
  24. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_calibration.py +0 -0
  25. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_chunking.py +0 -0
  26. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_cluster_gcn.py +0 -0
  27. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_continuous_rl_algorithms.py +0 -0
  28. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_dashboard.py +0 -0
  29. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_dashboard_metadata.py +0 -0
  30. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_dataset_cache.py +0 -0
  31. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_dataset_docs_claims.py +0 -0
  32. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_dataset_download_mocked.py +0 -0
  33. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_dataset_registry.py +0 -0
  34. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_datasets_base.py +0 -0
  35. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_devices.py +0 -0
  36. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_distributed_compat.py +0 -0
  37. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_distributed_helpers.py +0 -0
  38. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_distributed_smoke.py +0 -0
  39. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_documentation_claims.py +0 -0
  40. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_edge_features.py +0 -0
  41. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_edge_weight.py +0 -0
  42. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_estimators_v05.py +0 -0
  43. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_evolutionary_graph_optimization.py +0 -0
  44. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_evolutionary_history_v132.py +0 -0
  45. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_experiments.py +0 -0
  46. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_explainability.py +0 -0
  47. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_factories.py +0 -0
  48. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_folder_datasets.py +0 -0
  49. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_gat_chunking.py +0 -0
  50. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_generation_rl_benchmarks_smoke.py +0 -0
  51. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_gnn_families.py +0 -0
  52. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_gradients.py +0 -0
  53. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph.py +0 -0
  54. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_action_spaces.py +0 -0
  55. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_api.py +0 -0
  56. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_builders.py +0 -0
  57. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_generation_data_model.py +0 -0
  58. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_generation_metrics.py +0 -0
  59. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_rl_algorithms.py +0 -0
  60. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_rl_environments.py +0 -0
  61. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_transformer_v027.py +0 -0
  62. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graph_utils.py +0 -0
  63. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_graphsaint.py +0 -0
  64. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_han_hgt_overfit.py +0 -0
  65. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_hard_negative_sampling.py +0 -0
  66. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_hetero_batch.py +0 -0
  67. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_hetero_layers.py +0 -0
  68. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_hetero_layers_v05.py +0 -0
  69. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_hetero_sampling.py +0 -0
  70. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_imports.py +0 -0
  71. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_io_graphml_v120.py +0 -0
  72. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_benchmarks_smoke.py +0 -0
  73. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_data_model.py +0 -0
  74. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_datasets.py +0 -0
  75. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_evaluation.py +0 -0
  76. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_feature_aware_v131.py +0 -0
  77. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_gnn_integration.py +0 -0
  78. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_hpo_v130.py +0 -0
  79. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_models.py +0 -0
  80. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_multimodal.py +0 -0
  81. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_negative_sampling.py +0 -0
  82. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_reasoning.py +0 -0
  83. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_rescal_v120.py +0 -0
  84. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_simple_v130.py +0 -0
  85. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_temporal.py +0 -0
  86. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_kg_training.py +0 -0
  87. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_layers.py +0 -0
  88. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_loader_feature_store_integration.py +0 -0
  89. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_loader_robustness_v110.py +0 -0
  90. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_loaders_feature_store.py +0 -0
  91. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_matching_coloring_flow.py +0 -0
  92. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_math.py +0 -0
  93. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_math_correctness_v110.py +0 -0
  94. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_math_invariants_v030.py +0 -0
  95. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_metrics.py +0 -0
  96. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_mining_centrality.py +0 -0
  97. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_mining_core.py +0 -0
  98. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_mining_generators_spectral.py +0 -0
  99. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_mining_graph_learning.py +0 -0
  100. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_mining_paths_algorithms.py +0 -0
  101. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_mining_structural.py +0 -0
  102. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_model_zoo.py +0 -0
  103. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_models.py +0 -0
  104. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_negative_sampling.py +0 -0
  105. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_neural_mining.py +0 -0
  106. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_neural_mining_batched.py +0 -0
  107. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_node2vec_kg_hypergraph.py +0 -0
  108. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_ogb_tgb_wrappers.py +0 -0
  109. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_packaging.py +0 -0
  110. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_performance_smoke.py +0 -0
  111. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_plotting.py +0 -0
  112. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_public_benchmarks.py +0 -0
  113. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_pyg_dgl_ogb_wrappers.py +0 -0
  114. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_random_walk_sample.py +0 -0
  115. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_readme_links.py +0 -0
  116. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_release_validation_v030.py +0 -0
  117. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_reproducibility.py +0 -0
  118. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_rl_baselines.py +0 -0
  119. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_rl_callbacks_v120.py +0 -0
  120. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_rl_high_level_api.py +0 -0
  121. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_rollout_buffer.py +0 -0
  122. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_sampling.py +0 -0
  123. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_sampling_loaders.py +0 -0
  124. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_sparse_backend_select.py +0 -0
  125. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_sparse_vgae_rgcn.py +0 -0
  126. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_synthetic_datasets.py +0 -0
  127. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_temporal_sampling.py +0 -0
  128. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_temporal_v025.py +0 -0
  129. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_temporal_v05.py +0 -0
  130. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_tgn_tgat_overfit.py +0 -0
  131. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_time_encoding.py +0 -0
  132. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_tiny_overfit_v030.py +0 -0
  133. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_torchvision_wrappers.py +0 -0
  134. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_tracking.py +0 -0
  135. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_training.py +0 -0
  136. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_transforms.py +0 -0
  137. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_user_friendly_llm_snippets.py +0 -0
  138. {tgraphx-1.3.2 → tgraphx-1.3.4}/tests/test_v024_features.py +0 -0
  139. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/__main__.py +0 -0
  140. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/algorithms/__init__.py +0 -0
  141. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/algorithms/connectivity.py +0 -0
  142. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/algorithms/structural.py +0 -0
  143. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/algorithms/traversal.py +0 -0
  144. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/benchmarks/public.py +0 -0
  145. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/calibration.py +0 -0
  146. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/cluster_gcn.py +0 -0
  147. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/__init__.py +0 -0
  148. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/dataloader.py +0 -0
  149. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/graph.py +0 -0
  150. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/graph_utils.py +0 -0
  151. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/hetero_batch.py +0 -0
  152. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/hetero_graph.py +0 -0
  153. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/temporal.py +0 -0
  154. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/temporal_batch.py +0 -0
  155. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/core/utils.py +0 -0
  156. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/dashboard/__init__.py +0 -0
  157. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/dashboard/__main__.py +0 -0
  158. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/dashboard/app.py +0 -0
  159. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/dashboard/static/dashboard.css +0 -0
  160. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/dashboard/static/dashboard.js +0 -0
  161. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/__init__.py +0 -0
  162. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/base.py +0 -0
  163. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/cache.py +0 -0
  164. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/converters.py +0 -0
  165. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/dgl_wrappers.py +0 -0
  166. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/download.py +0 -0
  167. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/errors.py +0 -0
  168. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/folder.py +0 -0
  169. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/metadata.py +0 -0
  170. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/ogb_wrappers.py +0 -0
  171. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/pyg_wrappers.py +0 -0
  172. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/registry.py +0 -0
  173. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/synthetic.py +0 -0
  174. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/datasets/torchvision_wrappers.py +0 -0
  175. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/distributed.py +0 -0
  176. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/doctor.py +0 -0
  177. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/__init__.py +0 -0
  178. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_data.py +0 -0
  179. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_diagnostics.py +0 -0
  180. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_discovery.py +0 -0
  181. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_exceptions.py +0 -0
  182. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_models.py +0 -0
  183. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/easy/_results.py +0 -0
  184. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/__init__.py +0 -0
  185. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/base.py +0 -0
  186. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/early_stopping.py +0 -0
  187. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/label_propagation.py +0 -0
  188. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/node2vec.py +0 -0
  189. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/splits.py +0 -0
  190. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/estimators/vgae.py +0 -0
  191. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/__init__.py +0 -0
  192. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/algorithms.py +0 -0
  193. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/config.py +0 -0
  194. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/fitness.py +0 -0
  195. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/genome.py +0 -0
  196. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/high_level_api.py +0 -0
  197. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/metrics.py +0 -0
  198. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/multi_objective.py +0 -0
  199. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/operators.py +0 -0
  200. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/reports.py +0 -0
  201. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/evolutionary/selection.py +0 -0
  202. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/__init__.py +0 -0
  203. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/callbacks.py +0 -0
  204. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/checkpoints.py +0 -0
  205. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/cli.py +0 -0
  206. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/config.py +0 -0
  207. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/grid.py +0 -0
  208. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/runner.py +0 -0
  209. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/experiments/summarize.py +0 -0
  210. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/__init__.py +0 -0
  211. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/attention.py +0 -0
  212. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/edge_attribution.py +0 -0
  213. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/export.py +0 -0
  214. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/integrated_gradients.py +0 -0
  215. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/patch_heatmap.py +0 -0
  216. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/saliency.py +0 -0
  217. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/explain/utils.py +0 -0
  218. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/feature_store.py +0 -0
  219. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/__init__.py +0 -0
  220. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/actions.py +0 -0
  221. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/classical.py +0 -0
  222. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/config.py +0 -0
  223. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/data_model.py +0 -0
  224. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/high_level_api.py +0 -0
  225. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/metrics.py +0 -0
  226. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/neural.py +0 -0
  227. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/projectors.py +0 -0
  228. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/generation/reports.py +0 -0
  229. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/graph_builders.py +0 -0
  230. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/graphsaint.py +0 -0
  231. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/hetero_sampling.py +0 -0
  232. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/interop.py +0 -0
  233. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/io/__init__.py +0 -0
  234. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/io/graphml.py +0 -0
  235. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/__init__.py +0 -0
  236. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/data.py +0 -0
  237. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/datasets.py +0 -0
  238. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/evaluation.py +0 -0
  239. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/gnn.py +0 -0
  240. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/hpo.py +0 -0
  241. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/losses.py +0 -0
  242. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/models.py +0 -0
  243. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/multimodal.py +0 -0
  244. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/projectors.py +0 -0
  245. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/reasoning.py +0 -0
  246. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/reports.py +0 -0
  247. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/sampling.py +0 -0
  248. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/temporal.py +0 -0
  249. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/kg/trainer.py +0 -0
  250. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/__init__.py +0 -0
  251. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/_dim.py +0 -0
  252. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/_scatter.py +0 -0
  253. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/aggregator.py +0 -0
  254. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/appnp.py +0 -0
  255. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/attention_message.py +0 -0
  256. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/base.py +0 -0
  257. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/conv_message.py +0 -0
  258. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/factory.py +0 -0
  259. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/gat.py +0 -0
  260. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/gatv2.py +0 -0
  261. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/gin.py +0 -0
  262. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/graph_transformer.py +0 -0
  263. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/han.py +0 -0
  264. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/hetero.py +0 -0
  265. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/hetero_readout.py +0 -0
  266. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/hgt.py +0 -0
  267. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/pooling.py +0 -0
  268. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/rgcn.py +0 -0
  269. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/safe_pool.py +0 -0
  270. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/sage.py +0 -0
  271. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/temporal_readout.py +0 -0
  272. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/transformer_encodings.py +0 -0
  273. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/layers/vector_gcn.py +0 -0
  274. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/learned_graph.py +0 -0
  275. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/loaders.py +0 -0
  276. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/__init__.py +0 -0
  277. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/classification.py +0 -0
  278. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/link_prediction.py +0 -0
  279. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/ogb.py +0 -0
  280. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/ranking.py +0 -0
  281. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/regression.py +0 -0
  282. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/metrics/reports.py +0 -0
  283. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/anomaly.py +0 -0
  284. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/api.py +0 -0
  285. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/centrality.py +0 -0
  286. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/communities.py +0 -0
  287. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/embeddings.py +0 -0
  288. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/frequent.py +0 -0
  289. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/generators.py +0 -0
  290. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/graph_io.py +0 -0
  291. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/graph_learning.py +0 -0
  292. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/hetero.py +0 -0
  293. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/hypergraph.py +0 -0
  294. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/knowledge_graph.py +0 -0
  295. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/label_prop.py +0 -0
  296. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/link_prediction.py +0 -0
  297. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/matching_coloring.py +0 -0
  298. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/motifs.py +0 -0
  299. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/neural.py +0 -0
  300. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/node2vec.py +0 -0
  301. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/paths.py +0 -0
  302. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/patterns.py +0 -0
  303. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/prototype.py +0 -0
  304. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/random_walk.py +0 -0
  305. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/reports.py +0 -0
  306. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/sequence_models.py +0 -0
  307. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/similarity.py +0 -0
  308. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/spectral.py +0 -0
  309. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/structural.py +0 -0
  310. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/structural_encodings.py +0 -0
  311. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/temporal.py +0 -0
  312. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/mining/vgae.py +0 -0
  313. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/__init__.py +0 -0
  314. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/cnn_encoder.py +0 -0
  315. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/cnn_gnn_model.py +0 -0
  316. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/edge_predictor.py +0 -0
  317. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/factory.py +0 -0
  318. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/graph_classifier.py +0 -0
  319. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/hetero_models.py +0 -0
  320. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/model_zoo.py +0 -0
  321. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/node_classifier.py +0 -0
  322. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/pre_encoder.py +0 -0
  323. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/regressors.py +0 -0
  324. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/models/temporal_models.py +0 -0
  325. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/performance.py +0 -0
  326. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/plotting/__init__.py +0 -0
  327. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/plotting/graph.py +0 -0
  328. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/plotting/layouts.py +0 -0
  329. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/plotting/mining.py +0 -0
  330. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/plotting/utils.py +0 -0
  331. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/reproducibility.py +0 -0
  332. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/__init__.py +0 -0
  333. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/__init__.py +0 -0
  334. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/actor_critic.py +0 -0
  335. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/base.py +0 -0
  336. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/baselines.py +0 -0
  337. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/continuous.py +0 -0
  338. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/dqn.py +0 -0
  339. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/ppo.py +0 -0
  340. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/reinforce.py +0 -0
  341. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/algorithms/replay_buffer.py +0 -0
  342. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/callbacks.py +0 -0
  343. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/config.py +0 -0
  344. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/__init__.py +0 -0
  345. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/base.py +0 -0
  346. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/coloring.py +0 -0
  347. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/continuous.py +0 -0
  348. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/generation.py +0 -0
  349. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/kg_reasoning.py +0 -0
  350. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/max_cut.py +0 -0
  351. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/navigation.py +0 -0
  352. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/shortest_path.py +0 -0
  353. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/environments/vertex_cover.py +0 -0
  354. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/exploration/__init__.py +0 -0
  355. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/exploration/strategies.py +0 -0
  356. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/high_level_api.py +0 -0
  357. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/metrics.py +0 -0
  358. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/networks/__init__.py +0 -0
  359. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/networks/actor_critic.py +0 -0
  360. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/networks/policy.py +0 -0
  361. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/networks/projectors.py +0 -0
  362. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/networks/qnetwork.py +0 -0
  363. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/networks/value.py +0 -0
  364. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/rl/reports.py +0 -0
  365. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/sampling.py +0 -0
  366. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/sampling_loaders.py +0 -0
  367. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/sampling_negative.py +0 -0
  368. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/sparse.py +0 -0
  369. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/temporal/__init__.py +0 -0
  370. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/temporal/tgat.py +0 -0
  371. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/temporal/tgn.py +0 -0
  372. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/temporal/time_encoding.py +0 -0
  373. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/temporal_sampling.py +0 -0
  374. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/tracking.py +0 -0
  375. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/training.py +0 -0
  376. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/__init__.py +0 -0
  377. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/compose.py +0 -0
  378. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/features.py +0 -0
  379. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/graph.py +0 -0
  380. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/patch.py +0 -0
  381. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/positional.py +0 -0
  382. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx/transforms/splits.py +0 -0
  383. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx.egg-info/dependency_links.txt +0 -0
  384. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx.egg-info/entry_points.txt +0 -0
  385. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx.egg-info/requires.txt +0 -0
  386. {tgraphx-1.3.2 → tgraphx-1.3.4}/tgraphx.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tgraphx
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: Tensor-aware graph neural networks preserving spatial node feature layouts
5
5
  Author-email: Arash Sajjadi <arash.sajjadi@usask.ca>
6
6
  Maintainer-email: Arash Sajjadi <arash.sajjadi@usask.ca>
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "tgraphx"
7
7
  # Keep this in sync with tgraphx/__init__.py::__version__
8
- version = "1.3.2"
8
+ version = "1.3.4"
9
9
  description = "Tensor-aware graph neural networks preserving spatial node feature layouts"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
@@ -0,0 +1,417 @@
1
+ """Colab regression tests (v1.3.4).
2
+
3
+ One test per public snippet that was reported as broken from a Colab / PyPI install.
4
+ These tests pin the exact user-facing code patterns so they can never silently regress.
5
+
6
+ All tests must:
7
+ - Use only public APIs (importable after `pip install tgraphx`).
8
+ - Run on CPU without network.
9
+ - Be fast (< 30 seconds each).
10
+ - Fail with a clear message if the bug reappears.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import math
16
+ import tempfile
17
+ from pathlib import Path
18
+
19
+ import pytest
20
+ import torch
21
+ import torch.nn.functional as F
22
+
23
+
24
+ # ── Bug A — Easy Mode deterministic reproducibility ───────────────────────────
25
+
26
+
27
+ class TestReproducibilityDetministicCPU:
28
+ """Same seed + deterministic=True + device=cpu must give identical final loss."""
29
+
30
+ def _run_once(self):
31
+ import tgraphx as tgx
32
+ from tgraphx.reproducibility import set_seed
33
+
34
+ set_seed(42, deterministic=True)
35
+ data = tgx.easy.synthetic_tensor_node_classification(
36
+ num_nodes=64, node_shape=(4, 4, 4), num_classes=3,
37
+ num_edges=200, seed=42,
38
+ )
39
+ r = tgx.easy.train_node_classifier(
40
+ data, epochs=2, batch_size=16, fanouts=[5, 3],
41
+ verbose=False, seed=42, deterministic=True, device="cpu",
42
+ )
43
+ return r
44
+
45
+ def test_deterministic_cpu_exact_match(self):
46
+ r1 = self._run_once()
47
+ r2 = self._run_once()
48
+ diff = abs(r1.metrics["loss"] - r2.metrics["loss"])
49
+ assert diff < 1e-7, f"CPU deterministic loss diff too large: {diff:.2e}"
50
+
51
+ def test_synthetic_data_reproducible(self):
52
+ import tgraphx as tgx
53
+ d1 = tgx.easy.synthetic_tensor_node_classification(num_nodes=32, seed=7)
54
+ d2 = tgx.easy.synthetic_tensor_node_classification(num_nodes=32, seed=7)
55
+ assert torch.equal(d1.node_features, d2.node_features)
56
+ assert torch.equal(d1.edge_index, d2.edge_index)
57
+
58
+ def test_set_seed_returns_state_dict(self):
59
+ from tgraphx.reproducibility import set_seed
60
+ state = set_seed(42, deterministic=True)
61
+ assert isinstance(state, dict)
62
+ assert state["seed"] == 42
63
+ assert state["deterministic"] is True
64
+ assert "torch_version" in state
65
+
66
+ def test_train_stores_reproducibility_state(self):
67
+ r = self._run_once()
68
+ state = r.config.get("reproducibility_state", {})
69
+ assert state.get("seed") == 42
70
+ assert state.get("deterministic") is True
71
+
72
+ def test_exact_user_colab_snippet(self):
73
+ """Exact snippet from the reproducibility bug report."""
74
+ import tgraphx as tgx
75
+ from tgraphx.reproducibility import set_seed
76
+
77
+ results = []
78
+ for _ in range(2):
79
+ set_seed(42, deterministic=True)
80
+ data = tgx.easy.synthetic_tensor_node_classification(
81
+ num_nodes=64, node_shape=(4, 4, 4), num_classes=3,
82
+ num_edges=200, seed=42,
83
+ )
84
+ r = tgx.easy.train_node_classifier(
85
+ data, epochs=2, batch_size=16, fanouts=[5, 3],
86
+ verbose=False, seed=42, deterministic=True, device="cpu",
87
+ )
88
+ results.append(r.metrics["loss"])
89
+
90
+ diff = abs(results[0] - results[1])
91
+ assert diff < 1e-7, diff
92
+
93
+
94
+ # ── Bug B — NSGA-II composite_fitness misuse ──────────────────────────────────
95
+
96
+
97
+ class TestNSGAIIOptimizer:
98
+ """NSGAIIOptimizer requires a list of objectives, not composite_fitness directly."""
99
+
100
+ def _genome(self, seed=0):
101
+ from tgraphx.evolutionary import GraphGenome
102
+ torch.manual_seed(seed)
103
+ return GraphGenome(edge_index=torch.randint(0, 8, (2, 10)), num_nodes=8)
104
+
105
+ def test_nsga_with_list_of_objectives(self):
106
+ from tgraphx.evolutionary import NSGAIIOptimizer, EvolutionConfig, connectivity_fitness
107
+ objectives = [connectivity_fitness, connectivity_fitness]
108
+ config = EvolutionConfig(population_size=6, n_generations=4, seed=0)
109
+ pop = [self._genome(i) for i in range(6)]
110
+ r = NSGAIIOptimizer(config, objectives).optimize(pop)
111
+ assert r.pareto_front is not None
112
+ assert r.best_fitness >= 0.0
113
+ assert len(r.history) == 4
114
+
115
+ def test_ga_history_works(self):
116
+ from tgraphx.evolutionary import (
117
+ GeneticAlgorithmOptimizer, GeneticAlgorithmConfig, connectivity_fitness,
118
+ )
119
+ config = GeneticAlgorithmConfig(population_size=6, n_generations=5, seed=42)
120
+ pop = [self._genome(i) for i in range(6)]
121
+ r = GeneticAlgorithmOptimizer(config, connectivity_fitness).optimize(pop)
122
+ assert len(r.history) == 5
123
+ assert "generation" in r.history[0]
124
+ assert "best_fitness" in r.history[0]
125
+
126
+ def test_nsga_history_works(self):
127
+ from tgraphx.evolutionary import NSGAIIOptimizer, EvolutionConfig, connectivity_fitness
128
+ config = EvolutionConfig(population_size=4, n_generations=3, seed=0)
129
+ pop = [self._genome(i) for i in range(4)]
130
+ r = NSGAIIOptimizer(config, [connectivity_fitness]).optimize(pop)
131
+ assert len(r.history) == 3
132
+
133
+ def test_evolution_result_to_dict_json_serializable(self):
134
+ from tgraphx.evolutionary import (
135
+ GeneticAlgorithmOptimizer, GeneticAlgorithmConfig, connectivity_fitness,
136
+ )
137
+ config = GeneticAlgorithmConfig(population_size=4, n_generations=3, seed=0)
138
+ pop = [self._genome(i) for i in range(4)]
139
+ r = GeneticAlgorithmOptimizer(config, connectivity_fitness).optimize(pop)
140
+ d = r.to_dict()
141
+ json.dumps(d) # must not raise
142
+
143
+
144
+ # ── Bug C — GraphML exception handling ───────────────────────────────────────
145
+
146
+
147
+ class TestGraphMLExceptionHandling:
148
+ """ValueError from write_graphml must be formatted with str(e), not e[:120]."""
149
+
150
+ def test_str_exception_not_slice(self, tmp_path):
151
+ """Ensures str(e)[:120] works; e[:120] would TypeError in real code."""
152
+ from tgraphx import Graph
153
+ from tgraphx.io import write_graphml
154
+
155
+ x_spatial = torch.randn(4, 3, 8, 8)
156
+ g = Graph(node_features=x_spatial,
157
+ edge_index=torch.tensor([[0, 1], [1, 2]]))
158
+
159
+ caught = None
160
+ try:
161
+ write_graphml(g, tmp_path / "test.graphml", include_tensor_features=True)
162
+ except ValueError as e:
163
+ caught = e
164
+ msg = str(e)[:120] # must not raise TypeError
165
+ assert "multi-dimensional" in msg or "rank" in msg or "shape" in msg or "tensor" in msg.lower()
166
+
167
+ assert caught is not None, "Expected ValueError for [N,C,H,W] tensor features"
168
+
169
+ def test_1d_features_round_trip(self, tmp_path):
170
+ """1-D node features must round-trip through GraphML without error."""
171
+ from tgraphx import Graph
172
+ from tgraphx.io import write_graphml, read_graphml
173
+
174
+ x = torch.tensor([[0.5], [1.0], [0.25]])
175
+ ei = torch.tensor([[0, 1], [1, 2]], dtype=torch.long)
176
+ g = Graph(node_features=x, edge_index=ei)
177
+ path = tmp_path / "roundtrip.graphml"
178
+ write_graphml(g, path, include_tensor_features=True)
179
+ g2 = read_graphml(path)
180
+ assert g2.num_nodes == 3
181
+ assert g2.num_edges == 2
182
+
183
+
184
+ # ── Bug D — motif_profile / graph_summary import ─────────────────────────────
185
+
186
+
187
+ class TestMiningImports:
188
+ def test_motif_profile_importable(self):
189
+ from tgraphx.mining import motif_profile
190
+ assert callable(motif_profile)
191
+
192
+ def test_graph_summary_importable(self):
193
+ from tgraphx.mining import graph_summary
194
+ assert callable(graph_summary)
195
+
196
+ def test_graph_summary_returns_expected_keys(self):
197
+ from tgraphx.mining import graph_summary
198
+ ei = torch.tensor([[0, 1, 2, 3, 4], [1, 2, 3, 4, 0]], dtype=torch.long)
199
+ s = graph_summary(ei, num_nodes=5)
200
+ for key in ("num_nodes", "num_edges"):
201
+ assert key in s, f"Missing key: {key}"
202
+ assert s["num_nodes"] == 5
203
+
204
+ def test_motif_profile_returns_dict_with_triangles(self):
205
+ from tgraphx.mining import motif_profile
206
+ # Triangle graph
207
+ ei = torch.tensor([[0, 1, 2, 1, 2, 0], [1, 2, 0, 0, 1, 2]], dtype=torch.long)
208
+ m = motif_profile(ei, num_nodes=3)
209
+ assert isinstance(m, dict)
210
+ # There is at least one triangle
211
+ assert m.get("triangles", 0) > 0 or "triangles" in str(m)
212
+
213
+ def test_degree_statistics_importable(self):
214
+ from tgraphx.mining import degree_statistics
215
+ ei = torch.tensor([[0, 0, 0, 0], [1, 2, 3, 4]], dtype=torch.long)
216
+ s = degree_statistics(ei, num_nodes=5)
217
+ assert isinstance(s, dict)
218
+
219
+ def test_notebook_20_smoke(self):
220
+ """Exact imports from notebook 20."""
221
+ from tgraphx.mining import motif_profile, graph_summary
222
+ from tgraphx.mining.matching_coloring import enumerate_maximal_cliques
223
+ import torch
224
+ N = 5
225
+ ei = torch.tensor([[0, 1, 2, 3, 4], [1, 2, 3, 4, 0]], dtype=torch.long)
226
+ summary = graph_summary(ei, num_nodes=N)
227
+ assert isinstance(summary, dict)
228
+ profile = motif_profile(ei, num_nodes=N)
229
+ assert isinstance(profile, dict)
230
+ cliques = enumerate_maximal_cliques(ei, num_nodes=N, max_nodes=50)
231
+ assert isinstance(cliques, list)
232
+
233
+
234
+ # ── Bug E — wl_subtree_kernel import ─────────────────────────────────────────
235
+
236
+
237
+ class TestWLSubtreeKernel:
238
+ def test_importable(self):
239
+ from tgraphx.mining import wl_subtree_kernel
240
+ assert callable(wl_subtree_kernel)
241
+
242
+ def test_identical_graphs_higher_than_different(self):
243
+ from tgraphx.mining import wl_subtree_kernel
244
+ ei_ring5 = torch.tensor([[0, 1, 2, 3, 4], [1, 2, 3, 4, 0]], dtype=torch.long)
245
+ ei_ring3 = torch.tensor([[0, 1, 2], [1, 2, 0]], dtype=torch.long)
246
+ k_self = wl_subtree_kernel(ei_ring5, 5, ei_ring5, 5, h=3)
247
+ k_cross = wl_subtree_kernel(ei_ring5, 5, ei_ring3, 3, h=3)
248
+ assert k_self >= k_cross
249
+
250
+ def test_symmetry(self):
251
+ from tgraphx.mining import wl_subtree_kernel
252
+ ei_a = torch.tensor([[0, 1], [1, 2]], dtype=torch.long)
253
+ ei_b = torch.tensor([[0, 1, 2], [1, 2, 0]], dtype=torch.long)
254
+ k_ab = wl_subtree_kernel(ei_a, 3, ei_b, 3, h=2)
255
+ k_ba = wl_subtree_kernel(ei_b, 3, ei_a, 3, h=2)
256
+ assert abs(k_ab - k_ba) < 1e-6
257
+
258
+ def test_normalize_finite(self):
259
+ from tgraphx.mining import wl_subtree_kernel
260
+ ei = torch.tensor([[0, 1], [1, 0]], dtype=torch.long)
261
+ k = wl_subtree_kernel(ei, 2, ei, 2, h=2, normalize=True)
262
+ assert math.isfinite(k)
263
+
264
+ def test_notebook_21_smoke(self):
265
+ """Exact import from notebook 21."""
266
+ from tgraphx.mining.kernels import wl_subtree_kernel
267
+ # Must work through kernels module too via alias; check from mining
268
+ from tgraphx.mining import wl_subtree_kernel as wl_sk
269
+ ei5 = torch.tensor([[0, 1, 2, 3, 4], [1, 2, 3, 4, 0]], dtype=torch.long)
270
+ ei3 = torch.tensor([[0, 1, 2], [1, 2, 0]], dtype=torch.long)
271
+ k = wl_sk(ei5, 5, ei3, 3, h=3)
272
+ assert k >= 0
273
+
274
+
275
+ # ── Bug F — centrality_summary import ────────────────────────────────────────
276
+
277
+
278
+ class TestCentralitySummary:
279
+ def test_importable(self):
280
+ from tgraphx.mining import centrality_summary
281
+ assert callable(centrality_summary)
282
+
283
+ def test_star_center_is_top(self):
284
+ from tgraphx.mining import centrality_summary
285
+ # Star graph: node 0 is center
286
+ star_ei = torch.tensor([[0, 0, 0, 0, 1, 2, 3, 4],
287
+ [1, 2, 3, 4, 0, 0, 0, 0]], dtype=torch.long)
288
+ cs = centrality_summary(star_ei, num_nodes=5)
289
+ assert cs["top_degree_nodes"][0][0] == 0, "Star center must be top"
290
+
291
+ def test_returns_expected_keys(self):
292
+ from tgraphx.mining import centrality_summary
293
+ ei = torch.tensor([[0, 1], [1, 2]], dtype=torch.long)
294
+ cs = centrality_summary(ei, num_nodes=3)
295
+ for key in ("num_nodes", "num_edges", "top_degree_nodes"):
296
+ assert key in cs
297
+
298
+ def test_notebook_22_smoke(self):
299
+ """Exact imports from notebook 22."""
300
+ from tgraphx.mining import degree_statistics, centrality_summary
301
+ star_ei = torch.tensor([[0, 0, 0, 0, 1, 2, 3, 4],
302
+ [1, 2, 3, 4, 0, 0, 0, 0]], dtype=torch.long)
303
+ ds = degree_statistics(star_ei, num_nodes=5)
304
+ cs = centrality_summary(star_ei, num_nodes=5)
305
+ assert isinstance(ds, dict)
306
+ assert isinstance(cs, dict)
307
+
308
+
309
+ # ── Bug G — Package-level benchmark suite ────────────────────────────────────
310
+
311
+
312
+ class TestPackageBenchmarkSuite:
313
+ def test_importable_from_package(self):
314
+ from tgraphx.benchmarks import run_v13_benchmark_suite
315
+ assert callable(run_v13_benchmark_suite)
316
+
317
+ def test_runs_outside_repo_tree(self, tmp_path):
318
+ """Simulate running from outside repo: use package API, not repo script."""
319
+ import subprocess, sys
320
+ result = subprocess.run(
321
+ [sys.executable, "-c",
322
+ "from tgraphx.benchmarks import run_v13_benchmark_suite;"
323
+ "data = run_v13_benchmark_suite(small=True, return_dict=True);"
324
+ "assert 'benchmarks' in data;"
325
+ "print('OK', len(data['benchmarks']))"],
326
+ capture_output=True, text=True, timeout=120,
327
+ cwd=str(tmp_path), # Run from an empty temp dir, not repo
328
+ )
329
+ assert result.returncode == 0, f"STDERR: {result.stderr[:300]}"
330
+ assert "OK" in result.stdout
331
+
332
+ def test_returns_expected_schema(self):
333
+ from tgraphx.benchmarks import run_v13_benchmark_suite
334
+ data = run_v13_benchmark_suite(small=True, return_dict=True)
335
+ assert "suite" in data
336
+ assert "benchmarks" in data
337
+ for row in data["benchmarks"]:
338
+ assert "name" in row
339
+ assert "status" in row
340
+
341
+ def test_json_serializable(self):
342
+ from tgraphx.benchmarks import run_v13_benchmark_suite
343
+ data = run_v13_benchmark_suite(small=True, return_dict=True)
344
+ json.dumps(data, default=str)
345
+
346
+ def test_python_m_cli(self, tmp_path):
347
+ """python -m tgraphx.benchmarks.run_v13_benchmark_suite --small --json"""
348
+ import subprocess, sys
349
+ out_file = tmp_path / "out.json"
350
+ result = subprocess.run(
351
+ [sys.executable, "-m", "tgraphx.benchmarks.run_v13_benchmark_suite",
352
+ "--small", "--out", str(out_file)],
353
+ capture_output=True, text=True, timeout=120,
354
+ cwd=str(tmp_path),
355
+ )
356
+ assert result.returncode == 0, f"STDERR: {result.stderr[:300]}"
357
+ data = json.loads(out_file.read_text())
358
+ assert "benchmarks" in data
359
+
360
+
361
+ # ── Bug H — ConvMessagePassing / NeighborLoader seed-node loss ───────────────
362
+
363
+
364
+ class TestConvMessagePassingNeighborLoader:
365
+ def test_seed_logits_no_unsafe_slicing(self):
366
+ """batch.seed_logits(logits) must work; logits[:batch_size] would be wrong."""
367
+ from tgraphx import Graph, NeighborLoader
368
+ import torch.nn as nn
369
+
370
+ torch.manual_seed(0)
371
+ N, D = 50, 8
372
+ x = torch.randn(N, D)
373
+ ei = torch.randint(0, N, (2, 200))
374
+ y = torch.randint(0, 3, (N,))
375
+ g = Graph(node_features=x, edge_index=ei, y=y)
376
+
377
+ loader = NeighborLoader(g, fanouts=[5, 3], batch_size=8, seed=0)
378
+ linear = nn.Linear(D, 3)
379
+ opt = torch.optim.Adam(linear.parameters(), lr=1e-2)
380
+
381
+ batch = next(iter(loader))
382
+ logits = linear(batch.node_features)
383
+ # Correct API: batch.seed_logits extracts supervision-node logits.
384
+ seed_logits = batch.seed_logits(logits)
385
+ assert seed_logits.shape[0] == batch.batch_size
386
+ loss = F.cross_entropy(seed_logits, batch.seed_y)
387
+ loss.backward()
388
+ assert torch.isfinite(loss)
389
+
390
+
391
+ # ── Bug I — Feature-aware KG regression (v1.3.1 fix) ────────────────────────
392
+
393
+
394
+ class TestFeatureAwareKGRegression:
395
+ def test_entity_features_score_triples(self):
396
+ """Exact snippet from v1.3.1 Colab bug report."""
397
+ from tgraphx.kg import KnowledgeGraph, TransEModel
398
+
399
+ torch.manual_seed(0)
400
+ N_e, N_r, N_t = 10, 3, 30
401
+ heads = torch.randint(0, N_e, (N_t,))
402
+ rels = torch.randint(0, N_r, (N_t,))
403
+ tails = torch.randint(0, N_e, (N_t,))
404
+ entity_features = {"visual": torch.randn(N_e, 32)}
405
+
406
+ kg = KnowledgeGraph.from_hrt(
407
+ heads, rels, tails,
408
+ num_entities=N_e, num_relations=N_r,
409
+ entity_features=entity_features,
410
+ )
411
+
412
+ model = TransEModel(N_e, N_r, embedding_dim=16, entity_feature_dim=32)
413
+ triples = torch.stack([heads, rels, tails], dim=1)
414
+ scores = model.score_triples(triples, entity_features=kg.entity_features["visual"])
415
+ assert scores.shape == (N_t,)
416
+ scores.mean().backward()
417
+ assert model.entity_proj.proj.weight.grad is not None
@@ -1,6 +1,14 @@
1
- """Notebook structural tests (v1.3).
1
+ """Notebook structural tests (v1.3 / v1.3.4+).
2
2
 
3
3
  Validates every notebook/*.ipynb without executing code.
4
+
5
+ The notebooks/ folder is NOT tracked in git (it is gitignored as of v1.3.4).
6
+ These tests skip gracefully when notebooks/ is absent so that CI remains
7
+ green in the absence of locally generated notebooks.
8
+
9
+ To run locally, first generate notebooks with::
10
+
11
+ python tools/generate_notebooks.py
4
12
  """
5
13
  from __future__ import annotations
6
14
 
@@ -11,26 +19,36 @@ from pathlib import Path
11
19
  import pytest
12
20
 
13
21
  NOTEBOOKS_DIR = Path("notebooks")
14
- NOTEBOOKS = sorted(NOTEBOOKS_DIR.glob("*.ipynb"))
22
+ _NOTEBOOKS_PRESENT = NOTEBOOKS_DIR.exists() and bool(list(NOTEBOOKS_DIR.glob("*.ipynb")))
23
+ NOTEBOOKS = sorted(NOTEBOOKS_DIR.glob("*.ipynb")) if NOTEBOOKS_DIR.exists() else []
15
24
 
16
25
  _PRIVATE_PATH_RE = re.compile(r"/home/[a-zA-Z0-9_]+|/Users/[a-zA-Z0-9_]+")
17
26
  _SECRET_RE = re.compile(r"(?i)(token\s*=|password\s*=|api_key\s*=)['\"]?\w{8,}")
18
27
 
28
+ _skip_if_absent = pytest.mark.skipif(
29
+ not _NOTEBOOKS_PRESENT,
30
+ reason="notebooks/ not found locally; generate with: python tools/generate_notebooks.py",
31
+ )
32
+
19
33
 
20
34
  @pytest.fixture(scope="module")
21
35
  def all_notebooks():
22
- assert NOTEBOOKS_DIR.exists(), f"notebooks/ directory not found: {NOTEBOOKS_DIR}"
23
- assert len(NOTEBOOKS) > 0, f"No .ipynb files in {NOTEBOOKS_DIR}"
36
+ if not _NOTEBOOKS_PRESENT:
37
+ pytest.skip("notebooks/ not found")
24
38
  return {nb.name: json.loads(nb.read_text(encoding="utf-8")) for nb in NOTEBOOKS}
25
39
 
26
40
 
27
41
  class TestNotebooksExist:
28
- def test_notebooks_dir_exists(self):
42
+ def test_notebooks_dir_exists_or_skips(self):
43
+ if not _NOTEBOOKS_PRESENT:
44
+ pytest.skip("notebooks/ not found locally — OK in CI without local notebooks")
29
45
  assert NOTEBOOKS_DIR.exists()
30
46
 
47
+ @_skip_if_absent
31
48
  def test_at_least_7_notebooks(self):
32
49
  assert len(NOTEBOOKS) >= 7, f"Expected >=7 notebooks, found {len(NOTEBOOKS)}"
33
50
 
51
+ @_skip_if_absent
34
52
  @pytest.mark.parametrize("name", [
35
53
  "01_easy_tensor_node_classification.ipynb",
36
54
  "02_image_patch_tensor_graph.ipynb",
@@ -106,6 +124,7 @@ class TestNotebookContent:
106
124
 
107
125
 
108
126
  class TestNotebookValidationTool:
127
+ @_skip_if_absent
109
128
  def test_validate_notebooks_passes(self):
110
129
  import subprocess, sys
111
130
  result = subprocess.run(
@@ -0,0 +1,137 @@
1
+ """Reproducibility tests for Easy Mode (v1.3.3).
2
+
3
+ Tests that:
4
+ 1. Synthetic data creation is seeded deterministically.
5
+ 2. NeighborLoader with same seed produces identical batches.
6
+ 3. CPU + deterministic=True gives exact same loss across two runs.
7
+ 4. Reproducibility state is recorded in result.config.
8
+ 5. CUDA (if available) at least produces finite results in deterministic mode.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import pytest
13
+ import torch
14
+ import tgraphx as tgx
15
+ from tgraphx.reproducibility import set_seed
16
+
17
+
18
+ # ── 1. Synthetic data reproducibility ────────────────────────────────────────
19
+
20
+
21
+ class TestSyntheticDataReproducibility:
22
+ def test_same_seed_same_features(self):
23
+ d1 = tgx.easy.synthetic_tensor_node_classification(
24
+ num_nodes=32, node_shape=(4, 4, 4), num_classes=3, num_edges=100, seed=42,
25
+ )
26
+ d2 = tgx.easy.synthetic_tensor_node_classification(
27
+ num_nodes=32, node_shape=(4, 4, 4), num_classes=3, num_edges=100, seed=42,
28
+ )
29
+ assert torch.equal(d1.node_features, d2.node_features)
30
+ assert torch.equal(d1.edge_index, d2.edge_index)
31
+ assert torch.equal(d1.node_labels, d2.node_labels)
32
+
33
+ def test_different_seed_different_output(self):
34
+ d1 = tgx.easy.synthetic_tensor_node_classification(num_nodes=50, seed=0)
35
+ d2 = tgx.easy.synthetic_tensor_node_classification(num_nodes=50, seed=99)
36
+ # With different seeds the features should differ (with overwhelmingly high probability).
37
+ assert not torch.equal(d1.node_features, d2.node_features)
38
+
39
+
40
+ # ── 2. NeighborLoader batch order reproducibility ────────────────────────────
41
+
42
+
43
+ class TestNeighborLoaderReproducibility:
44
+ def test_same_seed_same_first_batch_seed_nodes(self):
45
+ from tgraphx import Graph, NeighborLoader
46
+ x = torch.randn(100, 8)
47
+ ei = torch.randint(0, 100, (2, 400))
48
+ y = torch.randint(0, 3, (100,))
49
+ g = Graph(node_features=x, edge_index=ei, y=y)
50
+
51
+ loader_a = NeighborLoader(g, fanouts=[5, 3], batch_size=8, shuffle=True, seed=7)
52
+ loader_b = NeighborLoader(g, fanouts=[5, 3], batch_size=8, shuffle=True, seed=7)
53
+
54
+ seeds_a = [b.seed_node_ids.clone() for b in loader_a]
55
+ seeds_b = [b.seed_node_ids.clone() for b in loader_b]
56
+ assert len(seeds_a) == len(seeds_b)
57
+ for a, b in zip(seeds_a, seeds_b):
58
+ assert torch.equal(a, b)
59
+
60
+
61
+ # ── 3. Easy Mode CPU deterministic reproducibility ───────────────────────────
62
+
63
+
64
+ class TestEasyModeDeterministicCPU:
65
+ def _run(self):
66
+ set_seed(42, deterministic=True)
67
+ data = tgx.easy.synthetic_tensor_node_classification(
68
+ num_nodes=32, node_shape=(4, 4, 4), num_classes=3, num_edges=100, seed=42,
69
+ )
70
+ return tgx.easy.train_node_classifier(
71
+ data, epochs=2, batch_size=8, fanouts=[4, 2],
72
+ verbose=False, seed=42, deterministic=True, device="cpu",
73
+ )
74
+
75
+ def test_deterministic_cpu_exact_match(self):
76
+ r1 = self._run()
77
+ r2 = self._run()
78
+ diff = abs(r1.metrics["loss"] - r2.metrics["loss"])
79
+ assert diff < 1e-7, f"CPU deterministic diff too large: {diff:.2e}"
80
+
81
+ def test_deterministic_flag_in_config(self):
82
+ r = self._run()
83
+ assert r.config.get("deterministic") is True
84
+
85
+ def test_reproducibility_state_recorded(self):
86
+ r = self._run()
87
+ state = r.config.get("reproducibility_state", {})
88
+ assert state.get("seed") == 42
89
+ assert state.get("deterministic") is True
90
+ assert "torch_version" in state
91
+ assert "cuda_available" in state
92
+
93
+ def test_default_non_deterministic_still_runs(self):
94
+ """Default deterministic=False must not crash."""
95
+ data = tgx.easy.synthetic_tensor_node_classification(
96
+ num_nodes=32, node_shape=(4, 4, 4), num_classes=2, num_edges=100, seed=0,
97
+ )
98
+ r = tgx.easy.train_node_classifier(
99
+ data, epochs=1, batch_size=8, fanouts=[3, 2],
100
+ verbose=False, seed=0, device="cpu",
101
+ )
102
+ assert "loss" in r.metrics
103
+ assert r.config.get("deterministic") is False
104
+
105
+
106
+ # ── 4. set_seed return value ──────────────────────────────────────────────────
107
+
108
+
109
+ class TestSetSeedReturnValue:
110
+ def test_returns_dict_with_required_keys(self):
111
+ state = set_seed(42, deterministic=True)
112
+ assert isinstance(state, dict)
113
+ assert state["seed"] == 42
114
+ assert state["deterministic"] is True
115
+ assert "torch_version" in state
116
+ assert "cuda_available" in state
117
+
118
+ def test_non_deterministic_mode(self):
119
+ state = set_seed(7, deterministic=False)
120
+ assert state["deterministic"] is False
121
+
122
+
123
+ # ── 5. CUDA smoke (if available) ──────────────────────────────────────────────
124
+
125
+
126
+ class TestEasyModeDeviceCUDA:
127
+ @pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA unavailable")
128
+ def test_deterministic_cuda_finite_loss(self):
129
+ set_seed(42, deterministic=True)
130
+ data = tgx.easy.synthetic_tensor_node_classification(
131
+ num_nodes=32, node_shape=(4, 4, 4), num_classes=3, num_edges=100, seed=42,
132
+ )
133
+ r = tgx.easy.train_node_classifier(
134
+ data, epochs=1, batch_size=8, fanouts=[4, 2],
135
+ verbose=False, seed=42, deterministic=True, device="cuda",
136
+ )
137
+ assert torch.isfinite(torch.tensor(r.metrics["loss"]))
@@ -10,7 +10,7 @@ Common one-liner imports::
10
10
  """
11
11
 
12
12
  # Keep this in sync with [project].version in pyproject.toml.
13
- __version__ = "1.3.2"
13
+ __version__ = "1.3.4"
14
14
 
15
15
  # ── Core data structures ──────────────────────────────────────────────────────
16
16
  from .core.graph import Graph, GraphBatch
@@ -1,11 +1,17 @@
1
- """Public-benchmark integration helpers (OGB / TGB).
1
+ """Public-benchmark integration helpers (OGB / TGB) and v1.3 benchmark suite.
2
2
 
3
3
  Optional, dependency-light evaluator wrappers around the official
4
4
  benchmark packages. Importing this module never triggers a network
5
5
  call; callers must explicitly download datasets via the upstream
6
6
  packages.
7
7
 
8
- Stability: Beta (v0.5.0+).
8
+ The v1.3 benchmark suite is available as a package-level function so it
9
+ can be called without a cloned repository::
10
+
11
+ from tgraphx.benchmarks import run_v13_benchmark_suite
12
+ results = run_v13_benchmark_suite(small=True, return_dict=True)
13
+
14
+ Stability: Beta (v0.5.0+). ``run_v13_benchmark_suite`` — Beta (v1.3.4+).
9
15
  """
10
16
  from __future__ import annotations
11
17
 
@@ -15,10 +21,12 @@ from .public import (
15
21
  OGBGraphEvaluator,
16
22
  TGBLinkEvaluator,
17
23
  )
24
+ from .suite import run_v13_benchmark_suite
18
25
 
19
26
  __all__ = [
20
27
  "OGBNodeEvaluator",
21
28
  "OGBLinkEvaluator",
22
29
  "OGBGraphEvaluator",
23
30
  "TGBLinkEvaluator",
31
+ "run_v13_benchmark_suite",
24
32
  ]