b1-method 0.1.0__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.
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: b1-method
3
+ Version: 0.1.0
4
+ Summary: Domain-independent convergent derivation of canonical basis vectors from heterogeneous observations
5
+ Author-email: "Kafkas M. Caprazli" <caprazli@cosmologic.pro>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://cosmologic.pro
8
+ Keywords: measurement theory,dimensional analysis,convergent derivation,psychometrics,factor analysis,topology
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Scientific/Engineering
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+
20
+ # b1-method
21
+
22
+ Domain-independent convergent derivation of canonical basis vectors from K independent sources.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pip install b1-method
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```python
33
+ from b1_method import B1Analysis
34
+
35
+ alignment = {
36
+ "Extraversion": ["Y", "Y", "Y", "Y", "Y", "Y"],
37
+ "Agreeableness": ["Y", "Y", "Y*", "Y", "Y", "Y"],
38
+ "Conscientiousness": ["Y", "Y", "Y", "Y", "Y", "Y"],
39
+ "Neuroticism": ["Y", "Y", "Y*", "N*", "Y", "Y"],
40
+ "Openness": ["Y", "Y", "Y", "N*", "Y", "Y"],
41
+ "Honesty-Humility": ["N", "N", "Y", "Y*", "N", "N"],
42
+ }
43
+
44
+ result = B1Analysis(alignment, domain="Personality").run()
45
+ B1Analysis.print_report(result)
46
+ ```
47
+
48
+ ## CLI
49
+
50
+ ```bash
51
+ b1-method run alignment.csv --sources sources.csv --domain Personality
52
+ b1-method temporal alignment.csv --sources sources.csv --domain Personality
53
+ b1-method version
54
+ ```
55
+
56
+ ## How It Works
57
+
58
+ Given K independent source assessments proposing competing dimensional structures for the same domain, B1 produces a tier-classified, independence-verified basis:
59
+
60
+ - **Tier 1** (count >= ceil(2K/3)): Strong convergence — confirmed basis vectors
61
+ - **Tier 2** (count >= ceil(K/3)): Partial convergence — contested candidates
62
+ - **Tier 3** (count < ceil(K/3)): Weak/non-convergent — insufficient support
63
+
64
+ The number of Tier 1 candidates is a **lower bound** on the domain's dimensionality.
65
+
66
+ ## License
67
+
68
+ MIT
@@ -0,0 +1,49 @@
1
+ # b1-method
2
+
3
+ Domain-independent convergent derivation of canonical basis vectors from K independent sources.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install b1-method
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from b1_method import B1Analysis
15
+
16
+ alignment = {
17
+ "Extraversion": ["Y", "Y", "Y", "Y", "Y", "Y"],
18
+ "Agreeableness": ["Y", "Y", "Y*", "Y", "Y", "Y"],
19
+ "Conscientiousness": ["Y", "Y", "Y", "Y", "Y", "Y"],
20
+ "Neuroticism": ["Y", "Y", "Y*", "N*", "Y", "Y"],
21
+ "Openness": ["Y", "Y", "Y", "N*", "Y", "Y"],
22
+ "Honesty-Humility": ["N", "N", "Y", "Y*", "N", "N"],
23
+ }
24
+
25
+ result = B1Analysis(alignment, domain="Personality").run()
26
+ B1Analysis.print_report(result)
27
+ ```
28
+
29
+ ## CLI
30
+
31
+ ```bash
32
+ b1-method run alignment.csv --sources sources.csv --domain Personality
33
+ b1-method temporal alignment.csv --sources sources.csv --domain Personality
34
+ b1-method version
35
+ ```
36
+
37
+ ## How It Works
38
+
39
+ Given K independent source assessments proposing competing dimensional structures for the same domain, B1 produces a tier-classified, independence-verified basis:
40
+
41
+ - **Tier 1** (count >= ceil(2K/3)): Strong convergence — confirmed basis vectors
42
+ - **Tier 2** (count >= ceil(K/3)): Partial convergence — contested candidates
43
+ - **Tier 3** (count < ceil(K/3)): Weak/non-convergent — insufficient support
44
+
45
+ The number of Tier 1 candidates is a **lower bound** on the domain's dimensionality.
46
+
47
+ ## License
48
+
49
+ MIT
@@ -0,0 +1,26 @@
1
+ """
2
+ b1-method: Domain-Independent Convergent Derivation of Canonical Basis Vectors
3
+ ===============================================================================
4
+
5
+ Given K independent sources proposing competing dimensional structures for the
6
+ same domain, B1 produces a tier-classified, independence-verified, composite-
7
+ checked basis — a lower bound on the manifold's topological complexity.
8
+
9
+ Usage:
10
+ from b1_method import B1Analysis
11
+
12
+ analysis = B1Analysis.from_csv("sources.csv")
13
+ result = analysis.run()
14
+ result.print_report()
15
+
16
+ CLI:
17
+ b1-method run sources.csv
18
+ b1-method temporal sources.csv
19
+ """
20
+
21
+ __version__ = "0.1.0"
22
+
23
+ from b1_method.core import B1Analysis, B1Result
24
+ from b1_method.temporal import TemporalSimulation
25
+
26
+ __all__ = ["B1Analysis", "B1Result", "TemporalSimulation"]
@@ -0,0 +1,5 @@
1
+ """Allow running the B1 method package as ``python -m b1_method``."""
2
+
3
+ from b1_method.cli import main
4
+
5
+ main()
@@ -0,0 +1,245 @@
1
+ """
2
+ b1_method.cli — Command-line interface for the B1 method.
3
+
4
+ Entry points:
5
+ b1-method run <alignment.csv> [--sources <sources.csv>] [--domain <name>]
6
+ b1-method temporal <alignment.csv> --sources <sources.csv> [--ground-truth <gt.json>]
7
+ b1-method version
8
+
9
+ Designed for ``python -m b1_method`` or as a console_scripts entry point.
10
+ """
11
+
12
+ import argparse
13
+ import json
14
+ import os
15
+ import sys
16
+
17
+ from b1_method import __version__
18
+ from b1_method.core import B1Analysis
19
+ from b1_method.temporal import TemporalSimulation, print_temporal_report
20
+ from b1_method.io import (
21
+ load_alignment_csv,
22
+ load_sources_csv,
23
+ load_combined_csv,
24
+ save_report_json,
25
+ )
26
+
27
+
28
+ def _build_parser():
29
+ """Build the argument parser with subcommands."""
30
+ parser = argparse.ArgumentParser(
31
+ prog="b1-method",
32
+ description=(
33
+ "B1 Convergent Derivation Method: domain-independent derivation "
34
+ "of canonical basis vectors from K independent sources."
35
+ ),
36
+ )
37
+
38
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
39
+
40
+ # --- run ---
41
+ run_parser = subparsers.add_parser(
42
+ "run",
43
+ help="Run B1 analysis on an alignment matrix.",
44
+ description=(
45
+ "Load an alignment CSV (and optional sources CSV), run the full "
46
+ "B1 pipeline (C1-C5), and print the report."
47
+ ),
48
+ )
49
+ run_parser.add_argument(
50
+ "alignment_csv",
51
+ help="Path to the alignment matrix CSV file.",
52
+ )
53
+ run_parser.add_argument(
54
+ "--sources",
55
+ dest="sources_csv",
56
+ default=None,
57
+ help="Path to the sources metadata CSV file (optional).",
58
+ )
59
+ run_parser.add_argument(
60
+ "--domain",
61
+ default=None,
62
+ help="Domain name for the report header (e.g. 'Personality').",
63
+ )
64
+ run_parser.add_argument(
65
+ "--output", "-o",
66
+ default=None,
67
+ help="Path to save the JSON report (optional).",
68
+ )
69
+
70
+ # --- temporal ---
71
+ temporal_parser = subparsers.add_parser(
72
+ "temporal",
73
+ help="Run temporal holdout simulation.",
74
+ description=(
75
+ "Feed sources to B1 in chronological order and compare "
76
+ "intermediate verdicts against ground-truth findings."
77
+ ),
78
+ )
79
+ temporal_parser.add_argument(
80
+ "alignment_csv",
81
+ help="Path to the alignment matrix CSV file.",
82
+ )
83
+ temporal_parser.add_argument(
84
+ "--sources",
85
+ dest="sources_csv",
86
+ required=True,
87
+ help="Path to the sources metadata CSV file (required for temporal).",
88
+ )
89
+ temporal_parser.add_argument(
90
+ "--ground-truth",
91
+ dest="ground_truth",
92
+ default=None,
93
+ help=(
94
+ "Path to a JSON file mapping ground-truth questions to boolean "
95
+ "answers. If omitted, simulation runs without accuracy scoring."
96
+ ),
97
+ )
98
+ temporal_parser.add_argument(
99
+ "--domain",
100
+ default=None,
101
+ help="Domain name for the report header.",
102
+ )
103
+ temporal_parser.add_argument(
104
+ "--output", "-o",
105
+ default=None,
106
+ help="Path to save the JSON report (optional).",
107
+ )
108
+
109
+ # --- version ---
110
+ subparsers.add_parser(
111
+ "version",
112
+ help="Print the package version.",
113
+ )
114
+
115
+ return parser
116
+
117
+
118
+ def _cmd_run(args):
119
+ """Execute the 'run' subcommand."""
120
+ # Load alignment data
121
+ alignment, source_names = load_alignment_csv(args.alignment_csv)
122
+
123
+ # Load sources if provided
124
+ sources = None
125
+ if args.sources_csv:
126
+ sources = load_sources_csv(args.sources_csv)
127
+
128
+ # Build and run analysis
129
+ domain = args.domain or _guess_domain(args.alignment_csv)
130
+ analysis = B1Analysis(
131
+ alignment=alignment,
132
+ sources=sources,
133
+ domain=domain,
134
+ )
135
+ result = analysis.run()
136
+
137
+ # Print report
138
+ B1Analysis.print_report(result)
139
+
140
+ # Save JSON if requested
141
+ if args.output:
142
+ save_report_json(result, args.output)
143
+ print(f"\nReport saved to: {args.output}")
144
+
145
+ return 0
146
+
147
+
148
+ def _cmd_temporal(args):
149
+ """Execute the 'temporal' subcommand."""
150
+ # Load alignment and sources
151
+ alignment, source_names = load_alignment_csv(args.alignment_csv)
152
+ source_meta = load_sources_csv(args.sources_csv)
153
+
154
+ # Build temporal source dicts: merge metadata with per-source factor verdicts
155
+ # Alignment is {candidate: [s1_val, s2_val, ...]}, sources are ordered by CSV column
156
+ # TemporalSimulation expects each source dict to have a "factors" key
157
+ candidates = list(alignment.keys())
158
+ temporal_sources = []
159
+ for i, meta in enumerate(source_meta):
160
+ factors = {}
161
+ for candidate in candidates:
162
+ row = alignment[candidate]
163
+ factors[candidate] = row[i] if i < len(row) else "N"
164
+ temporal_sources.append({**meta, "factors": factors})
165
+
166
+ # Load ground truth if provided
167
+ ground_truth = {}
168
+ if args.ground_truth:
169
+ gt_path = os.path.expanduser(args.ground_truth)
170
+ if not os.path.isfile(gt_path):
171
+ print(f"Error: ground-truth file not found: {gt_path}",
172
+ file=sys.stderr)
173
+ return 1
174
+ with open(gt_path, "r", encoding="utf-8") as f:
175
+ ground_truth = json.load(f)
176
+
177
+ # Build and run simulation
178
+ domain = args.domain or _guess_domain(args.alignment_csv)
179
+ sim = TemporalSimulation(
180
+ domain_name=domain,
181
+ sources=temporal_sources,
182
+ ground_truth=ground_truth,
183
+ candidates=candidates,
184
+ )
185
+ result = sim.run()
186
+
187
+ # Print report
188
+ print_temporal_report(result)
189
+
190
+ # Save JSON if requested
191
+ if args.output:
192
+ save_report_json(result, args.output)
193
+ print(f"\nReport saved to: {args.output}")
194
+
195
+ return 0
196
+
197
+
198
+ def _cmd_version():
199
+ """Execute the 'version' subcommand."""
200
+ print(f"b1-method {__version__}")
201
+ return 0
202
+
203
+
204
+ def _guess_domain(filepath):
205
+ """Guess the domain name from a file path."""
206
+ basename = os.path.splitext(os.path.basename(filepath))[0]
207
+ # Strip common prefixes/suffixes
208
+ for prefix in ("b1_", "alignment_", "sources_"):
209
+ if basename.lower().startswith(prefix):
210
+ basename = basename[len(prefix):]
211
+ return basename.replace("_", " ").title()
212
+
213
+
214
+ def main():
215
+ """CLI entry point for the B1 method package."""
216
+ parser = _build_parser()
217
+ args = parser.parse_args()
218
+
219
+ if args.command is None:
220
+ parser.print_help()
221
+ return 1
222
+
223
+ try:
224
+ if args.command == "run":
225
+ return _cmd_run(args)
226
+ elif args.command == "temporal":
227
+ return _cmd_temporal(args)
228
+ elif args.command == "version":
229
+ return _cmd_version()
230
+ else:
231
+ parser.print_help()
232
+ return 1
233
+ except FileNotFoundError as e:
234
+ print(f"Error: {e}", file=sys.stderr)
235
+ return 1
236
+ except ValueError as e:
237
+ print(f"Error: {e}", file=sys.stderr)
238
+ return 1
239
+ except KeyboardInterrupt:
240
+ print("\nInterrupted.", file=sys.stderr)
241
+ return 130
242
+
243
+
244
+ if __name__ == "__main__":
245
+ sys.exit(main() or 0)