tgraphx 0.4.2__tar.gz → 0.4.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 (230) hide show
  1. {tgraphx-0.4.2 → tgraphx-0.4.4}/PKG-INFO +1 -1
  2. {tgraphx-0.4.2 → tgraphx-0.4.4}/pyproject.toml +1 -1
  3. tgraphx-0.4.4/tests/test_matching_coloring_flow.py +178 -0
  4. tgraphx-0.4.4/tests/test_mining_graph_learning.py +301 -0
  5. tgraphx-0.4.4/tests/test_mining_paths_algorithms.py +251 -0
  6. tgraphx-0.4.4/tests/test_node2vec_kg_hypergraph.py +285 -0
  7. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/__init__.py +1 -1
  8. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/__init__.py +112 -0
  9. tgraphx-0.4.4/tgraphx/mining/graph_io.py +309 -0
  10. tgraphx-0.4.4/tgraphx/mining/graph_learning.py +500 -0
  11. tgraphx-0.4.4/tgraphx/mining/hypergraph.py +198 -0
  12. tgraphx-0.4.4/tgraphx/mining/knowledge_graph.py +393 -0
  13. tgraphx-0.4.4/tgraphx/mining/matching_coloring.py +509 -0
  14. tgraphx-0.4.4/tgraphx/mining/node2vec.py +331 -0
  15. tgraphx-0.4.4/tgraphx/mining/paths.py +674 -0
  16. tgraphx-0.4.4/tgraphx/mining/sequence_models.py +340 -0
  17. tgraphx-0.4.4/tgraphx/mining/structural_encodings.py +295 -0
  18. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx.egg-info/PKG-INFO +1 -1
  19. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx.egg-info/SOURCES.txt +13 -0
  20. {tgraphx-0.4.2 → tgraphx-0.4.4}/LICENSE +0 -0
  21. {tgraphx-0.4.2 → tgraphx-0.4.4}/README.md +0 -0
  22. {tgraphx-0.4.2 → tgraphx-0.4.4}/setup.cfg +0 -0
  23. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_3d_support.py +0 -0
  24. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_algorithms.py +0 -0
  25. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_amp_compile.py +0 -0
  26. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_backward_compatibility.py +0 -0
  27. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_benchmark_smoke.py +0 -0
  28. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_chunking.py +0 -0
  29. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_dashboard.py +0 -0
  30. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_dashboard_metadata.py +0 -0
  31. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_dataset_cache.py +0 -0
  32. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_dataset_docs_claims.py +0 -0
  33. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_dataset_download_mocked.py +0 -0
  34. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_dataset_registry.py +0 -0
  35. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_datasets_base.py +0 -0
  36. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_devices.py +0 -0
  37. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_distributed_compat.py +0 -0
  38. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_documentation_claims.py +0 -0
  39. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_edge_features.py +0 -0
  40. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_edge_weight.py +0 -0
  41. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_experiments.py +0 -0
  42. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_explainability.py +0 -0
  43. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_factories.py +0 -0
  44. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_folder_datasets.py +0 -0
  45. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_gat_chunking.py +0 -0
  46. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_gnn_families.py +0 -0
  47. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_gradients.py +0 -0
  48. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_graph.py +0 -0
  49. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_graph_api.py +0 -0
  50. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_graph_builders.py +0 -0
  51. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_graph_transformer_v027.py +0 -0
  52. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_graph_utils.py +0 -0
  53. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_hard_negative_sampling.py +0 -0
  54. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_hetero_batch.py +0 -0
  55. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_hetero_layers.py +0 -0
  56. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_hetero_sampling.py +0 -0
  57. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_imports.py +0 -0
  58. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_layers.py +0 -0
  59. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_math.py +0 -0
  60. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_math_invariants_v030.py +0 -0
  61. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_metrics.py +0 -0
  62. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_mining_centrality.py +0 -0
  63. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_mining_core.py +0 -0
  64. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_mining_generators_spectral.py +0 -0
  65. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_mining_structural.py +0 -0
  66. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_model_zoo.py +0 -0
  67. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_models.py +0 -0
  68. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_negative_sampling.py +0 -0
  69. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_neural_mining.py +0 -0
  70. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_neural_mining_batched.py +0 -0
  71. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_packaging.py +0 -0
  72. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_performance_smoke.py +0 -0
  73. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_plotting.py +0 -0
  74. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_public_benchmarks.py +0 -0
  75. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_pyg_dgl_ogb_wrappers.py +0 -0
  76. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_random_walk_sample.py +0 -0
  77. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_release_validation_v030.py +0 -0
  78. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_reproducibility.py +0 -0
  79. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_sampling.py +0 -0
  80. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_sampling_loaders.py +0 -0
  81. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_synthetic_datasets.py +0 -0
  82. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_temporal_sampling.py +0 -0
  83. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_temporal_v025.py +0 -0
  84. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_time_encoding.py +0 -0
  85. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_tiny_overfit_v030.py +0 -0
  86. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_torchvision_wrappers.py +0 -0
  87. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_tracking.py +0 -0
  88. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_training.py +0 -0
  89. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_transforms.py +0 -0
  90. {tgraphx-0.4.2 → tgraphx-0.4.4}/tests/test_v024_features.py +0 -0
  91. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/algorithms/__init__.py +0 -0
  92. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/algorithms/connectivity.py +0 -0
  93. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/algorithms/structural.py +0 -0
  94. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/algorithms/traversal.py +0 -0
  95. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/__init__.py +0 -0
  96. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/dataloader.py +0 -0
  97. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/graph.py +0 -0
  98. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/graph_utils.py +0 -0
  99. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/hetero_batch.py +0 -0
  100. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/hetero_graph.py +0 -0
  101. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/temporal.py +0 -0
  102. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/temporal_batch.py +0 -0
  103. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/core/utils.py +0 -0
  104. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/dashboard/__init__.py +0 -0
  105. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/dashboard/__main__.py +0 -0
  106. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/dashboard/app.py +0 -0
  107. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/dashboard/static/dashboard.css +0 -0
  108. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/dashboard/static/dashboard.js +0 -0
  109. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/__init__.py +0 -0
  110. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/base.py +0 -0
  111. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/cache.py +0 -0
  112. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/converters.py +0 -0
  113. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/dgl_wrappers.py +0 -0
  114. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/download.py +0 -0
  115. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/errors.py +0 -0
  116. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/folder.py +0 -0
  117. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/metadata.py +0 -0
  118. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/ogb_wrappers.py +0 -0
  119. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/pyg_wrappers.py +0 -0
  120. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/registry.py +0 -0
  121. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/synthetic.py +0 -0
  122. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/datasets/torchvision_wrappers.py +0 -0
  123. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/distributed.py +0 -0
  124. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/__init__.py +0 -0
  125. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/callbacks.py +0 -0
  126. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/checkpoints.py +0 -0
  127. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/cli.py +0 -0
  128. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/config.py +0 -0
  129. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/grid.py +0 -0
  130. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/runner.py +0 -0
  131. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/experiments/summarize.py +0 -0
  132. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/__init__.py +0 -0
  133. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/attention.py +0 -0
  134. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/edge_attribution.py +0 -0
  135. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/export.py +0 -0
  136. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/integrated_gradients.py +0 -0
  137. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/patch_heatmap.py +0 -0
  138. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/saliency.py +0 -0
  139. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/explain/utils.py +0 -0
  140. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/graph_builders.py +0 -0
  141. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/hetero_sampling.py +0 -0
  142. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/interop.py +0 -0
  143. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/__init__.py +0 -0
  144. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/_dim.py +0 -0
  145. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/_scatter.py +0 -0
  146. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/aggregator.py +0 -0
  147. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/appnp.py +0 -0
  148. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/attention_message.py +0 -0
  149. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/base.py +0 -0
  150. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/conv_message.py +0 -0
  151. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/factory.py +0 -0
  152. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/gat.py +0 -0
  153. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/gatv2.py +0 -0
  154. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/gin.py +0 -0
  155. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/graph_transformer.py +0 -0
  156. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/hetero.py +0 -0
  157. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/hetero_readout.py +0 -0
  158. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/pooling.py +0 -0
  159. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/safe_pool.py +0 -0
  160. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/sage.py +0 -0
  161. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/temporal_readout.py +0 -0
  162. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/transformer_encodings.py +0 -0
  163. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/layers/vector_gcn.py +0 -0
  164. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/learned_graph.py +0 -0
  165. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/__init__.py +0 -0
  166. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/classification.py +0 -0
  167. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/link_prediction.py +0 -0
  168. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/ogb.py +0 -0
  169. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/ranking.py +0 -0
  170. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/regression.py +0 -0
  171. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/metrics/reports.py +0 -0
  172. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/anomaly.py +0 -0
  173. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/api.py +0 -0
  174. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/centrality.py +0 -0
  175. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/communities.py +0 -0
  176. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/embeddings.py +0 -0
  177. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/frequent.py +0 -0
  178. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/generators.py +0 -0
  179. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/hetero.py +0 -0
  180. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/kernels.py +0 -0
  181. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/label_prop.py +0 -0
  182. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/link_prediction.py +0 -0
  183. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/motifs.py +0 -0
  184. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/neural.py +0 -0
  185. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/patterns.py +0 -0
  186. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/prototype.py +0 -0
  187. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/random_walk.py +0 -0
  188. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/reports.py +0 -0
  189. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/similarity.py +0 -0
  190. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/spectral.py +0 -0
  191. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/structural.py +0 -0
  192. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/mining/temporal.py +0 -0
  193. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/__init__.py +0 -0
  194. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/cnn_encoder.py +0 -0
  195. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/cnn_gnn_model.py +0 -0
  196. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/edge_predictor.py +0 -0
  197. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/factory.py +0 -0
  198. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/graph_classifier.py +0 -0
  199. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/hetero_models.py +0 -0
  200. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/model_zoo.py +0 -0
  201. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/node_classifier.py +0 -0
  202. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/pre_encoder.py +0 -0
  203. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/regressors.py +0 -0
  204. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/models/temporal_models.py +0 -0
  205. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/performance.py +0 -0
  206. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/plotting/__init__.py +0 -0
  207. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/plotting/graph.py +0 -0
  208. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/plotting/layouts.py +0 -0
  209. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/plotting/mining.py +0 -0
  210. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/plotting/utils.py +0 -0
  211. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/reproducibility.py +0 -0
  212. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/sampling.py +0 -0
  213. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/sampling_loaders.py +0 -0
  214. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/sampling_negative.py +0 -0
  215. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/temporal/__init__.py +0 -0
  216. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/temporal/time_encoding.py +0 -0
  217. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/temporal_sampling.py +0 -0
  218. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/tracking.py +0 -0
  219. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/training.py +0 -0
  220. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/__init__.py +0 -0
  221. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/compose.py +0 -0
  222. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/features.py +0 -0
  223. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/graph.py +0 -0
  224. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/patch.py +0 -0
  225. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/positional.py +0 -0
  226. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx/transforms/splits.py +0 -0
  227. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx.egg-info/dependency_links.txt +0 -0
  228. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx.egg-info/entry_points.txt +0 -0
  229. {tgraphx-0.4.2 → tgraphx-0.4.4}/tgraphx.egg-info/requires.txt +0 -0
  230. {tgraphx-0.4.2 → tgraphx-0.4.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: 0.4.2
3
+ Version: 0.4.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 = "0.4.2"
8
+ version = "0.4.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,178 @@
1
+ """Tests for matching, coloring, clique, and max-flow algorithms."""
2
+ import pytest
3
+ import torch
4
+ from tgraphx.mining import (
5
+ greedy_maximal_matching,
6
+ bipartite_greedy_matching,
7
+ greedy_coloring,
8
+ welsh_powell_coloring,
9
+ greedy_maximal_independent_set,
10
+ enumerate_maximal_cliques,
11
+ edmonds_karp_max_flow,
12
+ min_cut_from_max_flow,
13
+ wl_isomorphism_test,
14
+ write_algorithm_report,
15
+ )
16
+
17
+
18
+ def _chain(N=4):
19
+ src = list(range(N-1)) + list(range(1, N))
20
+ dst = list(range(1, N)) + list(range(N-1))
21
+ return torch.tensor([src, dst], dtype=torch.long), N
22
+
23
+
24
+ def _triangle():
25
+ return torch.tensor([[0,1,2,1,2,0],[1,2,0,0,1,2]], dtype=torch.long), 3
26
+
27
+
28
+ class TestMatching:
29
+ def test_maximal_matching_chain(self):
30
+ ei, N = _chain()
31
+ m = greedy_maximal_matching(ei, N)
32
+ assert m.size(0) == 2
33
+ # Each node appears at most once.
34
+ all_nodes = m.flatten().tolist()
35
+ assert len(set(all_nodes)) == len(all_nodes)
36
+
37
+ def test_maximal_matching_empty(self):
38
+ ei = torch.zeros((2, 0), dtype=torch.long)
39
+ m = greedy_maximal_matching(ei, 4)
40
+ assert m.shape == (2, 0)
41
+
42
+ def test_bipartite_matching(self):
43
+ # Left: 0,1; Right: 2,3; edges: 0-2, 0-3, 1-2
44
+ ei = torch.tensor([[0, 0, 1], [2, 3, 2]], dtype=torch.long)
45
+ m = bipartite_greedy_matching(ei, num_nodes_left=2, num_nodes_right=2)
46
+ assert m.size(0) == 2
47
+ # At most 2 pairs.
48
+ assert m.size(1) <= 2
49
+
50
+
51
+ class TestColoring:
52
+ def test_greedy_chain_valid(self):
53
+ ei, N = _chain()
54
+ colors, nc = greedy_coloring(ei, N)
55
+ # Valid coloring: no adjacent nodes have same color.
56
+ src, dst = ei[0].tolist(), ei[1].tolist()
57
+ for u, v in zip(src, dst):
58
+ assert colors[u].item() != colors[v].item(), f"Conflict at ({u},{v})"
59
+
60
+ def test_greedy_triangle_three_colors_max(self):
61
+ ei, N = _triangle()
62
+ colors, nc = greedy_coloring(ei, N)
63
+ # Triangle needs exactly 3 colors.
64
+ assert nc <= 3
65
+ src, dst = ei[0].tolist(), ei[1].tolist()
66
+ for u, v in zip(src, dst):
67
+ assert colors[u].item() != colors[v].item()
68
+
69
+ def test_welsh_powell_valid(self):
70
+ ei, N = _chain()
71
+ colors, nc = welsh_powell_coloring(ei, N)
72
+ src, dst = ei[0].tolist(), ei[1].tolist()
73
+ for u, v in zip(src, dst):
74
+ assert colors[u].item() != colors[v].item()
75
+
76
+ def test_empty_graph_one_color(self):
77
+ ei = torch.zeros((2, 0), dtype=torch.long)
78
+ colors, nc = greedy_coloring(ei, 5)
79
+ assert nc == 1 # all nodes get color 0
80
+ assert colors.tolist() == [0, 0, 0, 0, 0]
81
+
82
+
83
+ class TestClique:
84
+ def test_independent_set_chain(self):
85
+ ei, N = _chain()
86
+ ind_set = greedy_maximal_independent_set(ei, N, seed=0)
87
+ # Valid independent set: no two adjacent members.
88
+ adj = set(zip(ei[0].tolist(), ei[1].tolist()))
89
+ members = set(ind_set.tolist())
90
+ for u in members:
91
+ for v in members:
92
+ assert (u, v) not in adj or u == v
93
+
94
+ def test_independent_set_triangle_size_one(self):
95
+ ei, N = _triangle()
96
+ ind_set = greedy_maximal_independent_set(ei, N, seed=0)
97
+ assert ind_set.size(0) == 1 # can't pick more than 1 from triangle
98
+
99
+ def test_enumerate_maximal_cliques_triangle(self):
100
+ ei, N = _triangle()
101
+ cliques = enumerate_maximal_cliques(ei, N)
102
+ # K3 has exactly one maximal clique: {0,1,2}.
103
+ assert len(cliques) == 1
104
+ assert cliques[0] == frozenset({0, 1, 2})
105
+
106
+ def test_enumerate_maximal_cliques_chain(self):
107
+ ei, N = _chain()
108
+ cliques = enumerate_maximal_cliques(ei, N)
109
+ # Chain: 0-1-2-3 → maximal cliques are edges: {0,1},{1,2},{2,3}.
110
+ assert len(cliques) == 3
111
+
112
+ def test_clique_enumeration_size_guard(self):
113
+ ei = torch.zeros((2, 0), dtype=torch.long)
114
+ with pytest.raises(ValueError, match="max_nodes"):
115
+ enumerate_maximal_cliques(ei, 51, max_nodes=50)
116
+
117
+
118
+ class TestMaxFlow:
119
+ def test_simple_flow(self):
120
+ # 0 → 1 (cap 3), 0 → 2 (cap 2), 1 → 3 (cap 2), 2 → 3 (cap 3)
121
+ ei = torch.tensor([[0, 0, 1, 2], [1, 2, 3, 3]], dtype=torch.long)
122
+ cap = torch.tensor([3.0, 2.0, 2.0, 3.0])
123
+ flow, _ = edmonds_karp_max_flow(ei, 4, cap, 0, 3)
124
+ # Max flow = 4 (3+2 paths capped by sink capacities 2+3).
125
+ # Actually: path 0→1→3 (cap=2), path 0→2→3 (cap=2) → flow=4.
126
+ assert abs(flow - 4.0) < 1e-6
127
+
128
+ def test_max_flow_min_cut(self):
129
+ ei = torch.tensor([[0, 0, 1, 2], [1, 2, 3, 3]], dtype=torch.long)
130
+ cap = torch.tensor([3.0, 2.0, 2.0, 3.0])
131
+ flow, S, T = min_cut_from_max_flow(ei, 4, cap, 0, 3)
132
+ assert 0 in S and 3 in T
133
+ assert abs(flow - 4.0) < 1e-6
134
+
135
+ def test_negative_capacity_raises(self):
136
+ ei = torch.tensor([[0], [1]], dtype=torch.long)
137
+ cap = torch.tensor([-1.0])
138
+ with pytest.raises(ValueError, match="non-negative"):
139
+ edmonds_karp_max_flow(ei, 2, cap, 0, 1)
140
+
141
+ def test_disconnected_source_sink(self):
142
+ ei = torch.zeros((2, 0), dtype=torch.long)
143
+ cap = torch.zeros(0)
144
+ flow, _ = edmonds_karp_max_flow(ei, 3, cap, 0, 2)
145
+ assert flow == 0.0
146
+
147
+ def test_size_guard(self):
148
+ ei = torch.zeros((2, 0), dtype=torch.long)
149
+ cap = torch.zeros(0)
150
+ with pytest.raises(ValueError, match="num_nodes"):
151
+ edmonds_karp_max_flow(ei, 501, cap, 0, 499)
152
+
153
+
154
+ class TestWLIsomorphism:
155
+ def test_identical_graphs(self):
156
+ ei, N = _triangle()
157
+ assert wl_isomorphism_test(ei, N, ei, N) is True
158
+
159
+ def test_different_sizes(self):
160
+ ei3, N3 = _triangle()
161
+ ei4, N4 = _chain(5)
162
+ assert wl_isomorphism_test(ei3, N3, ei4, N4) is False
163
+
164
+ def test_non_isomorphic_same_size(self):
165
+ # Path 4 vs Cycle 4.
166
+ ei_path, _ = _chain(4)
167
+ ei_cycle = torch.tensor([[0,1,2,3,1,2,3,0],[1,2,3,0,0,1,2,3]], dtype=torch.long)
168
+ # WL should distinguish these.
169
+ result = wl_isomorphism_test(ei_path, 4, ei_cycle, 4, num_iterations=3)
170
+ # Note: WL may or may not distinguish some graphs. Accept any bool.
171
+ assert isinstance(result, bool)
172
+
173
+ def test_write_algorithm_report(self, tmp_path):
174
+ p = write_algorithm_report(str(tmp_path / "algo.json"),
175
+ "greedy_coloring", num_colors=3)
176
+ import json; d = json.loads(open(p).read())
177
+ assert d["algorithm"] == "greedy_coloring"
178
+ assert d["num_colors"] == 3
@@ -0,0 +1,301 @@
1
+ """Tests for graph learning, self-supervised, and augmentation utilities."""
2
+ import pytest
3
+ import torch
4
+ from tgraphx.mining import (
5
+ contrastive_loss, supervised_contrastive_loss, triplet_loss,
6
+ bpr_loss, reconstruction_loss,
7
+ drop_edges, drop_nodes, mask_node_features, add_random_edges,
8
+ subgraph_sampling, DGIObjective, GraphCLObjective,
9
+ create_negative_pairs, create_positive_pairs_from_batch,
10
+ degree_encoding, random_walk_structural_encoding,
11
+ shortest_path_anchor_encoding, centrality_encoding,
12
+ StructuralEncodingModule, attach_structural_encodings,
13
+ GraphSequenceEncoder, GraphSequenceClassifier, GraphRNNEdgeGenerator,
14
+ bfs_sequence_encode, random_walk_sequence_encode, pad_sequences,
15
+ )
16
+
17
+
18
+ def _chain_ei(N=4):
19
+ src = list(range(N-1)) + list(range(1, N))
20
+ dst = list(range(1, N)) + list(range(N-1))
21
+ return torch.tensor([src, dst], dtype=torch.long), N
22
+
23
+
24
+ class TestContrastiveLosses:
25
+ def test_contrastive_loss_forward(self):
26
+ z1 = torch.randn(4, 8, requires_grad=True)
27
+ z2 = torch.randn(4, 8, requires_grad=True)
28
+ loss = contrastive_loss(z1, z2)
29
+ assert loss.dim() == 0
30
+ assert torch.isfinite(loss)
31
+
32
+ def test_contrastive_loss_backward(self):
33
+ z1 = torch.randn(4, 8, requires_grad=True)
34
+ z2 = torch.randn(4, 8, requires_grad=True)
35
+ loss = contrastive_loss(z1, z2)
36
+ loss.backward()
37
+ assert z1.grad is not None and torch.isfinite(z1.grad).all()
38
+
39
+ def test_contrastive_loss_batch_too_small(self):
40
+ z1 = torch.randn(1, 8)
41
+ z2 = torch.randn(1, 8)
42
+ with pytest.raises(ValueError, match="batch size"):
43
+ contrastive_loss(z1, z2)
44
+
45
+ def test_supervised_contrastive_loss(self):
46
+ emb = torch.randn(6, 8, requires_grad=True)
47
+ labels = torch.tensor([0, 0, 1, 1, 2, 2])
48
+ loss = supervised_contrastive_loss(emb, labels)
49
+ assert torch.isfinite(loss)
50
+ loss.backward()
51
+ assert emb.grad is not None
52
+
53
+ def test_triplet_loss(self):
54
+ a = torch.randn(4, 8, requires_grad=True)
55
+ p = torch.randn(4, 8, requires_grad=True)
56
+ n = torch.randn(4, 8, requires_grad=True)
57
+ loss = triplet_loss(a, p, n)
58
+ assert loss >= 0
59
+ loss.backward()
60
+ assert a.grad is not None
61
+
62
+ def test_bpr_loss(self):
63
+ pos = torch.randn(4, requires_grad=True)
64
+ neg = torch.randn(4, requires_grad=True)
65
+ loss = bpr_loss(pos, neg)
66
+ assert torch.isfinite(loss)
67
+ loss.backward()
68
+
69
+ def test_reconstruction_loss(self):
70
+ x = torch.randn(4, 8)
71
+ recon = torch.randn(4, 8, requires_grad=True)
72
+ loss = reconstruction_loss(x, recon)
73
+ assert torch.isfinite(loss)
74
+ loss.backward()
75
+
76
+
77
+ class TestAugmentations:
78
+ def test_drop_edges_deterministic(self):
79
+ ei, N = _chain_ei()
80
+ new1, _ = drop_edges(ei, p=0.3, seed=42)
81
+ new2, _ = drop_edges(ei, p=0.3, seed=42)
82
+ assert torch.equal(new1, new2)
83
+
84
+ def test_drop_edges_all(self):
85
+ ei, N = _chain_ei()
86
+ new_ei, _ = drop_edges(ei, p=1.0)
87
+ assert new_ei.size(1) == 0
88
+
89
+ def test_drop_edges_none(self):
90
+ ei, N = _chain_ei()
91
+ new_ei, _ = drop_edges(ei, p=0.0)
92
+ assert torch.equal(new_ei, ei)
93
+
94
+ def test_drop_nodes_shape(self):
95
+ ei, N = _chain_ei()
96
+ x = torch.randn(N, 4)
97
+ new_ei, new_N, new_x, kept = drop_nodes(ei, N, p=0.3, seed=0, node_features=x)
98
+ assert new_x.size(0) == new_N
99
+ assert new_ei.size(0) == 2
100
+
101
+ def test_drop_nodes_deterministic(self):
102
+ ei, N = _chain_ei()
103
+ _, _, _, k1 = drop_nodes(ei, N, p=0.3, seed=7)
104
+ _, _, _, k2 = drop_nodes(ei, N, p=0.3, seed=7)
105
+ assert torch.equal(k1, k2)
106
+
107
+ def test_mask_node_features(self):
108
+ x = torch.ones(5, 8)
109
+ masked, mask = mask_node_features(x, p=0.5, seed=0)
110
+ assert masked.shape == x.shape
111
+ assert mask.dtype == torch.bool
112
+ # Masked elements should be 0.
113
+ assert (masked[mask] == 0.0).all()
114
+ # Non-masked elements should be 1.
115
+ assert (masked[~mask] == 1.0).all()
116
+
117
+ def test_mask_features_deterministic(self):
118
+ x = torch.ones(5, 8)
119
+ _, m1 = mask_node_features(x, p=0.3, seed=1)
120
+ _, m2 = mask_node_features(x, p=0.3, seed=1)
121
+ assert torch.equal(m1, m2)
122
+
123
+ def test_add_random_edges(self):
124
+ ei, N = _chain_ei()
125
+ new_ei = add_random_edges(ei, N, num_add=3, seed=0)
126
+ assert new_ei.size(1) == ei.size(1) + 3
127
+
128
+ def test_subgraph_sampling(self):
129
+ ei, N = _chain_ei(8)
130
+ x = torch.randn(8, 4)
131
+ new_ei, new_N, new_x, sampled = subgraph_sampling(ei, 8, 4, seed=0, node_features=x)
132
+ assert new_N == 4
133
+ assert new_x.size(0) == 4
134
+ assert sampled.size(0) == 4
135
+
136
+
137
+ class TestSelfSupervisedObjectives:
138
+ def test_dgi_objective_forward(self):
139
+ dgi = DGIObjective(embed_dim=8, summary_dim=8)
140
+ pos_emb = torch.randn(5, 8, requires_grad=True)
141
+ neg_emb = torch.randn(5, 8, requires_grad=True)
142
+ loss = dgi(pos_emb, neg_emb)
143
+ assert torch.isfinite(loss)
144
+ loss.backward()
145
+ assert pos_emb.grad is not None
146
+
147
+ def test_graphcl_objective(self):
148
+ gcl = GraphCLObjective(project_dim=8)
149
+ z1 = torch.randn(4, 8, requires_grad=True)
150
+ z2 = torch.randn(4, 8, requires_grad=True)
151
+ loss = gcl(z1, z2)
152
+ assert torch.isfinite(loss)
153
+ loss.backward()
154
+
155
+
156
+ class TestStructuralEncodings:
157
+ def test_degree_encoding_shape(self):
158
+ ei, N = _chain_ei()
159
+ enc = degree_encoding(ei, N)
160
+ assert enc.shape == (N, 2)
161
+ assert enc.dtype == torch.float32
162
+
163
+ def test_degree_encoding_star_hub(self):
164
+ from tgraphx.mining import star_graph
165
+ ei, N = star_graph(5)
166
+ enc = degree_encoding(ei, N, normalize=False)
167
+ # Hub (node 0) should have highest degree.
168
+ assert float(enc[0, 0]) == 4.0
169
+
170
+ def test_centrality_encoding_shape(self):
171
+ ei, N = _chain_ei(6)
172
+ enc = centrality_encoding(ei, N, include=["degree", "pagerank"])
173
+ assert enc.shape == (N, 2)
174
+
175
+ def test_attach_concat(self):
176
+ ei, N = _chain_ei()
177
+ enc = degree_encoding(ei, N)
178
+ x = torch.randn(N, 6)
179
+ aug = attach_structural_encodings(x, enc)
180
+ assert aug.shape == (N, 8) # 6 + 2
181
+
182
+ def test_attach_spatial_raises(self):
183
+ ei, N = _chain_ei()
184
+ enc = degree_encoding(ei, N)
185
+ x = torch.randn(N, 3, 4, 4) # spatial
186
+ with pytest.raises(ValueError, match="mode='side'"):
187
+ attach_structural_encodings(x, enc, mode="concat")
188
+
189
+ def test_attach_side_mode(self):
190
+ ei, N = _chain_ei()
191
+ enc = degree_encoding(ei, N)
192
+ x = torch.randn(N, 3, 4, 4)
193
+ result = attach_structural_encodings(x, enc, mode="side")
194
+ assert result is enc
195
+
196
+ def test_structural_encoding_module(self):
197
+ mod = StructuralEncodingModule(in_dim=2, out_dim=8)
198
+ enc = torch.randn(5, 2)
199
+ out = mod(enc)
200
+ assert out.shape == (5, 8)
201
+ out.sum().backward()
202
+ assert all(p.grad is not None for p in mod.parameters())
203
+
204
+
205
+ class TestSequenceModels:
206
+ def test_bfs_sequence_encode(self):
207
+ ei, N = _chain_ei()
208
+ x = torch.randn(N, 4)
209
+ seq = bfs_sequence_encode(ei, N, node_features=x, start=0)
210
+ assert seq.shape[1] == 4
211
+ assert seq.shape[0] == N
212
+
213
+ def test_random_walk_sequence_encode(self):
214
+ ei, N = _chain_ei()
215
+ x = torch.randn(N, 4)
216
+ seq = random_walk_sequence_encode(ei, N, walk_length=5, node_features=x, seed=0)
217
+ assert seq.shape == (6, 4) # walk_length + 1
218
+
219
+ def test_pad_sequences(self):
220
+ seqs = [torch.randn(3, 4), torch.randn(5, 4), torch.randn(2, 4)]
221
+ padded, lengths = pad_sequences(seqs)
222
+ assert padded.shape == (3, 5, 4)
223
+ assert lengths.tolist() == [3, 5, 2]
224
+
225
+ def test_graph_sequence_encoder_forward(self):
226
+ enc = GraphSequenceEncoder(input_dim=4, hidden_dim=16, num_layers=2)
227
+ x = torch.randn(3, 7, 4)
228
+ out = enc(x)
229
+ assert out.shape == (3, 16)
230
+
231
+ def test_graph_sequence_encoder_backward(self):
232
+ enc = GraphSequenceEncoder(input_dim=4, hidden_dim=16, num_layers=2)
233
+ x = torch.randn(3, 7, 4)
234
+ out = enc(x)
235
+ out.sum().backward()
236
+ for p in enc.parameters():
237
+ assert p.grad is not None
238
+
239
+ def test_graph_sequence_classifier_overfit(self):
240
+ clf = GraphSequenceClassifier(input_dim=4, hidden_dim=32, num_classes=2)
241
+ opt = torch.optim.Adam(clf.parameters(), lr=1e-2)
242
+ # Class 0: mostly-zero sequences; class 1: mostly-one sequences.
243
+ x0 = torch.randn(3, 5, 4) * 0.01
244
+ x1 = torch.randn(3, 5, 4) + 5.0
245
+ X = torch.cat([x0, x1])
246
+ y = torch.tensor([0,0,0,1,1,1])
247
+ losses = []
248
+ for _ in range(30):
249
+ opt.zero_grad()
250
+ logits = clf(X)
251
+ loss = torch.nn.functional.cross_entropy(logits, y)
252
+ loss.backward()
253
+ opt.step()
254
+ losses.append(loss.detach().item())
255
+ assert losses[-1] < losses[0], f"Loss did not decrease: {losses[0]:.4f}→{losses[-1]:.4f}"
256
+
257
+ def test_graph_rnn_generator_shape(self):
258
+ gen = GraphRNNEdgeGenerator(max_nodes=8)
259
+ adj = gen.generate(5, seed=0)
260
+ assert adj.shape == (5, 5)
261
+ # Symmetric.
262
+ assert torch.equal(adj, adj.t())
263
+
264
+ def test_graph_rnn_generator_deterministic(self):
265
+ gen = GraphRNNEdgeGenerator(max_nodes=8)
266
+ adj1 = gen.generate(5, seed=42)
267
+ adj2 = gen.generate(5, seed=42)
268
+ assert torch.equal(adj1, adj2)
269
+
270
+ def test_graph_rnn_generator_backward(self):
271
+ gen = GraphRNNEdgeGenerator(max_nodes=6)
272
+ # Teacher-forcing training step.
273
+ opt = torch.optim.Adam(gen.parameters(), lr=1e-2)
274
+ # Target: random binary adjacency rows.
275
+ N = 4
276
+ B = 2
277
+ target = torch.zeros(B, N, 6)
278
+ for i in range(1, N):
279
+ target[:, i, :i] = (torch.rand(B, i) > 0.5).float()
280
+ logits, _ = gen(target)
281
+ # BCEWithLogits loss on upper triangle.
282
+ loss = torch.nn.functional.binary_cross_entropy_with_logits(logits, target)
283
+ loss.backward()
284
+ assert all(p.grad is not None for p in gen.parameters())
285
+
286
+
287
+ class TestNegativePairUtils:
288
+ def test_create_negative_pairs_no_false_neg(self):
289
+ ei = torch.tensor([[0,1],[1,2]], dtype=torch.long)
290
+ neg = create_negative_pairs(ei, num_nodes=4, num_neg=4, seed=0)
291
+ pos_set = {(int(ei[0,i]), int(ei[1,i])) for i in range(ei.size(1))}
292
+ neg_set = {(int(neg[0,i]), int(neg[1,i])) for i in range(neg.size(1))}
293
+ assert not (pos_set & neg_set)
294
+
295
+ def test_create_positive_pairs(self):
296
+ labels = torch.tensor([0, 0, 1, 1, 0])
297
+ pa, pb = create_positive_pairs_from_batch(labels)
298
+ assert pa.size(0) > 0
299
+ for a, b in zip(pa.tolist(), pb.tolist()):
300
+ assert labels[a] == labels[b]
301
+ assert a != b