quarterbit 0.1.0__tar.gz → 0.1.1__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.
- {quarterbit-0.1.0/quarterbit.egg-info → quarterbit-0.1.1}/PKG-INFO +1 -1
- {quarterbit-0.1.0 → quarterbit-0.1.1}/pyproject.toml +4 -1
- quarterbit-0.1.1/quarterbit/__init__.py +73 -0
- quarterbit-0.1.1/quarterbit/license.py +348 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1/quarterbit.egg-info}/PKG-INFO +1 -1
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit.egg-info/SOURCES.txt +2 -0
- quarterbit-0.1.1/quarterbit.egg-info/entry_points.txt +2 -0
- quarterbit-0.1.0/quarterbit/__init__.py +0 -94
- {quarterbit-0.1.0 → quarterbit-0.1.1}/LICENSE +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/README.md +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit/torch/__init__.py +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit/torch/functional.py +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit/torch/optim.py +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit/torch/utils.py +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit.egg-info/dependency_links.txt +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit.egg-info/requires.txt +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/quarterbit.egg-info/top_level.txt +0 -0
- {quarterbit-0.1.0 → quarterbit-0.1.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quarterbit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Precision optimizer for PyTorch - 1,000,000x more accurate than FP32
|
|
5
5
|
Author-email: Kyle Clouthier <info@quarterbit.dev>
|
|
6
6
|
License: Proprietary - Free tier available, commercial use requires license
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quarterbit"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1"
|
|
8
8
|
description = "Precision optimizer for PyTorch - 1,000,000x more accurate than FP32"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Proprietary - Free tier available, commercial use requires license"}
|
|
@@ -40,6 +40,9 @@ Documentation = "https://quarterbit.dev/docs"
|
|
|
40
40
|
[project.optional-dependencies]
|
|
41
41
|
dev = ["pytest", "build", "twine"]
|
|
42
42
|
|
|
43
|
+
[project.scripts]
|
|
44
|
+
quarterbit = "quarterbit.license:main"
|
|
45
|
+
|
|
43
46
|
[tool.setuptools.packages.find]
|
|
44
47
|
where = ["."]
|
|
45
48
|
include = ["quarterbit*"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QuarterBit
|
|
3
|
+
==========
|
|
4
|
+
|
|
5
|
+
Precision optimizer for PyTorch. 1,000,000x more accurate than FP32.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from quarterbit.torch import CompactEFTAdam
|
|
9
|
+
optimizer = CompactEFTAdam(model.parameters(), lr=1e-3)
|
|
10
|
+
|
|
11
|
+
Activate license:
|
|
12
|
+
quarterbit activate <YOUR_LICENSE_KEY>
|
|
13
|
+
|
|
14
|
+
Copyright (c) 2026 Clouthier Simulation Labs. All rights reserved.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__version__ = "0.1.1"
|
|
18
|
+
__author__ = "Kyle Clouthier"
|
|
19
|
+
__license__ = "Proprietary"
|
|
20
|
+
|
|
21
|
+
from .license import (
|
|
22
|
+
get_license_info,
|
|
23
|
+
activate,
|
|
24
|
+
deactivate,
|
|
25
|
+
check_license,
|
|
26
|
+
track_usage,
|
|
27
|
+
LicenseError,
|
|
28
|
+
UsageLimitError,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Get current license tier on import
|
|
32
|
+
_license_info = get_license_info()
|
|
33
|
+
_tier = _license_info["tier"]
|
|
34
|
+
|
|
35
|
+
# Show activation message for free tier (only once)
|
|
36
|
+
if not _license_info["activated"]:
|
|
37
|
+
import sys
|
|
38
|
+
if sys.stderr.isatty():
|
|
39
|
+
print(
|
|
40
|
+
f"QuarterBit v{__version__} (Free tier - {_license_info['usage']['gpu_hours_limit']} GPU-hrs/month)\n"
|
|
41
|
+
f"Activate: quarterbit activate <YOUR_KEY> | Get key: quarterbit.dev",
|
|
42
|
+
file=sys.stderr
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_version():
|
|
47
|
+
"""Get QuarterBit version."""
|
|
48
|
+
return __version__
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_tier():
|
|
52
|
+
"""Get current license tier."""
|
|
53
|
+
return _tier
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def is_available():
|
|
57
|
+
"""Check if QuarterBit GPU backend is available."""
|
|
58
|
+
try:
|
|
59
|
+
from .torch.utils import is_available as _gpu_available
|
|
60
|
+
return _gpu_available()
|
|
61
|
+
except ImportError:
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# Lazy imports for submodules
|
|
66
|
+
def __getattr__(name):
|
|
67
|
+
if name == "torch":
|
|
68
|
+
from . import torch
|
|
69
|
+
return torch
|
|
70
|
+
if name == "license":
|
|
71
|
+
from . import license
|
|
72
|
+
return license
|
|
73
|
+
raise AttributeError(f"module 'quarterbit' has no attribute '{name}'")
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QuarterBit License Management
|
|
3
|
+
=============================
|
|
4
|
+
|
|
5
|
+
Handles license activation, validation, and usage tracking.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
# Activate license (one-time)
|
|
9
|
+
quarterbit activate <LICENSE_KEY>
|
|
10
|
+
|
|
11
|
+
# Or in Python
|
|
12
|
+
from quarterbit.license import activate
|
|
13
|
+
activate("QB-XXXX-XXXX-XXXX")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import json
|
|
18
|
+
import hashlib
|
|
19
|
+
import platform
|
|
20
|
+
import urllib.request
|
|
21
|
+
import urllib.error
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from datetime import datetime, timedelta
|
|
24
|
+
from typing import Optional, Dict, Any
|
|
25
|
+
|
|
26
|
+
# License server endpoint
|
|
27
|
+
LICENSE_API = "https://us-central1-quarterbit.cloudfunctions.net"
|
|
28
|
+
|
|
29
|
+
# Local config directory
|
|
30
|
+
CONFIG_DIR = Path.home() / ".quarterbit"
|
|
31
|
+
LICENSE_FILE = CONFIG_DIR / "license.json"
|
|
32
|
+
USAGE_FILE = CONFIG_DIR / "usage.json"
|
|
33
|
+
|
|
34
|
+
# License tiers and limits
|
|
35
|
+
TIER_LIMITS = {
|
|
36
|
+
"FREE": {"gpu_hours_month": 10, "commercial": False},
|
|
37
|
+
"PRO": {"gpu_hours_month": 1000, "commercial": True},
|
|
38
|
+
"TEAM": {"gpu_hours_month": 10000, "commercial": True},
|
|
39
|
+
"ENTERPRISE": {"gpu_hours_month": float("inf"), "commercial": True},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_machine_id() -> str:
|
|
44
|
+
"""Generate a unique machine identifier."""
|
|
45
|
+
data = f"{platform.node()}-{platform.machine()}-{platform.processor()}"
|
|
46
|
+
return hashlib.sha256(data.encode()).hexdigest()[:16]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _ensure_config_dir():
|
|
50
|
+
"""Create config directory if it doesn't exist."""
|
|
51
|
+
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _load_license() -> Optional[Dict[str, Any]]:
|
|
55
|
+
"""Load license from local file."""
|
|
56
|
+
if not LICENSE_FILE.exists():
|
|
57
|
+
return None
|
|
58
|
+
try:
|
|
59
|
+
with open(LICENSE_FILE) as f:
|
|
60
|
+
return json.load(f)
|
|
61
|
+
except:
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _save_license(data: Dict[str, Any]):
|
|
66
|
+
"""Save license to local file."""
|
|
67
|
+
_ensure_config_dir()
|
|
68
|
+
with open(LICENSE_FILE, "w") as f:
|
|
69
|
+
json.dump(data, f, indent=2)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _load_usage() -> Dict[str, Any]:
|
|
73
|
+
"""Load usage tracking data."""
|
|
74
|
+
if not USAGE_FILE.exists():
|
|
75
|
+
return {"sessions": [], "gpu_seconds": 0, "month": datetime.now().strftime("%Y-%m")}
|
|
76
|
+
try:
|
|
77
|
+
with open(USAGE_FILE) as f:
|
|
78
|
+
data = json.load(f)
|
|
79
|
+
# Reset if new month
|
|
80
|
+
current_month = datetime.now().strftime("%Y-%m")
|
|
81
|
+
if data.get("month") != current_month:
|
|
82
|
+
data = {"sessions": [], "gpu_seconds": 0, "month": current_month}
|
|
83
|
+
return data
|
|
84
|
+
except:
|
|
85
|
+
return {"sessions": [], "gpu_seconds": 0, "month": datetime.now().strftime("%Y-%m")}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _save_usage(data: Dict[str, Any]):
|
|
89
|
+
"""Save usage tracking data."""
|
|
90
|
+
_ensure_config_dir()
|
|
91
|
+
with open(USAGE_FILE, "w") as f:
|
|
92
|
+
json.dump(data, f, indent=2)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def activate(license_key: str) -> Dict[str, Any]:
|
|
96
|
+
"""
|
|
97
|
+
Activate a license key.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
license_key: License key from quarterbit.dev dashboard
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
dict with activation status and tier info
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
ValueError: If license key is invalid
|
|
107
|
+
"""
|
|
108
|
+
if not license_key or not license_key.startswith("QB-"):
|
|
109
|
+
raise ValueError("Invalid license key format. Expected QB-XXXX-XXXX-XXXX")
|
|
110
|
+
|
|
111
|
+
machine_id = _get_machine_id()
|
|
112
|
+
|
|
113
|
+
# Validate with server
|
|
114
|
+
try:
|
|
115
|
+
req_data = json.dumps({
|
|
116
|
+
"licenseKey": license_key,
|
|
117
|
+
"machineId": machine_id,
|
|
118
|
+
"platform": platform.system(),
|
|
119
|
+
"pythonVersion": platform.python_version(),
|
|
120
|
+
}).encode()
|
|
121
|
+
|
|
122
|
+
req = urllib.request.Request(
|
|
123
|
+
f"{LICENSE_API}/activateLicense",
|
|
124
|
+
data=req_data,
|
|
125
|
+
headers={"Content-Type": "application/json"},
|
|
126
|
+
method="POST"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
130
|
+
result = json.loads(resp.read().decode())
|
|
131
|
+
|
|
132
|
+
except urllib.error.HTTPError as e:
|
|
133
|
+
error_body = e.read().decode() if e.fp else str(e)
|
|
134
|
+
raise ValueError(f"Activation failed: {error_body}")
|
|
135
|
+
except urllib.error.URLError:
|
|
136
|
+
raise ValueError("Cannot reach license server. Check your internet connection.")
|
|
137
|
+
|
|
138
|
+
if not result.get("valid"):
|
|
139
|
+
raise ValueError(result.get("error", "Invalid license key"))
|
|
140
|
+
|
|
141
|
+
# Save locally
|
|
142
|
+
license_data = {
|
|
143
|
+
"key": license_key,
|
|
144
|
+
"tier": result.get("tier", "FREE"),
|
|
145
|
+
"email": result.get("email"),
|
|
146
|
+
"activated_at": datetime.now().isoformat(),
|
|
147
|
+
"machine_id": machine_id,
|
|
148
|
+
"expires_at": result.get("expiresAt"),
|
|
149
|
+
}
|
|
150
|
+
_save_license(license_data)
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
"status": "activated",
|
|
154
|
+
"tier": license_data["tier"],
|
|
155
|
+
"email": license_data["email"],
|
|
156
|
+
"message": f"License activated! Tier: {license_data['tier']}"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def deactivate():
|
|
161
|
+
"""Remove license from this machine."""
|
|
162
|
+
if LICENSE_FILE.exists():
|
|
163
|
+
LICENSE_FILE.unlink()
|
|
164
|
+
if USAGE_FILE.exists():
|
|
165
|
+
USAGE_FILE.unlink()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_license_info() -> Dict[str, Any]:
|
|
169
|
+
"""Get current license information."""
|
|
170
|
+
license_data = _load_license()
|
|
171
|
+
|
|
172
|
+
if not license_data:
|
|
173
|
+
return {
|
|
174
|
+
"tier": "FREE",
|
|
175
|
+
"activated": False,
|
|
176
|
+
"limits": TIER_LIMITS["FREE"],
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
usage = _load_usage()
|
|
180
|
+
gpu_hours_used = usage.get("gpu_seconds", 0) / 3600
|
|
181
|
+
tier = license_data.get("tier", "FREE")
|
|
182
|
+
limits = TIER_LIMITS.get(tier, TIER_LIMITS["FREE"])
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
"tier": tier,
|
|
186
|
+
"activated": True,
|
|
187
|
+
"email": license_data.get("email"),
|
|
188
|
+
"key": license_data.get("key", "")[:10] + "...",
|
|
189
|
+
"activated_at": license_data.get("activated_at"),
|
|
190
|
+
"limits": limits,
|
|
191
|
+
"usage": {
|
|
192
|
+
"gpu_hours_used": round(gpu_hours_used, 2),
|
|
193
|
+
"gpu_hours_limit": limits["gpu_hours_month"],
|
|
194
|
+
"month": usage.get("month"),
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def check_license() -> bool:
|
|
200
|
+
"""
|
|
201
|
+
Check if license is valid for current usage.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
True if valid, raises exception if not
|
|
205
|
+
"""
|
|
206
|
+
info = get_license_info()
|
|
207
|
+
tier = info["tier"]
|
|
208
|
+
|
|
209
|
+
# Free tier always allowed (with limits enforced at usage)
|
|
210
|
+
if tier == "FREE":
|
|
211
|
+
return True
|
|
212
|
+
|
|
213
|
+
# Check if license expired (for paid tiers)
|
|
214
|
+
license_data = _load_license()
|
|
215
|
+
if license_data and license_data.get("expires_at"):
|
|
216
|
+
expires = datetime.fromisoformat(license_data["expires_at"].replace("Z", "+00:00"))
|
|
217
|
+
if datetime.now(expires.tzinfo) > expires:
|
|
218
|
+
raise LicenseError("License expired. Please renew at quarterbit.dev")
|
|
219
|
+
|
|
220
|
+
return True
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def track_usage(gpu_seconds: float):
|
|
224
|
+
"""
|
|
225
|
+
Track GPU usage for this session.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
gpu_seconds: Number of GPU seconds used
|
|
229
|
+
"""
|
|
230
|
+
usage = _load_usage()
|
|
231
|
+
usage["gpu_seconds"] = usage.get("gpu_seconds", 0) + gpu_seconds
|
|
232
|
+
usage["sessions"].append({
|
|
233
|
+
"timestamp": datetime.now().isoformat(),
|
|
234
|
+
"gpu_seconds": gpu_seconds,
|
|
235
|
+
})
|
|
236
|
+
# Keep last 100 sessions only
|
|
237
|
+
usage["sessions"] = usage["sessions"][-100:]
|
|
238
|
+
_save_usage(usage)
|
|
239
|
+
|
|
240
|
+
# Check limits
|
|
241
|
+
info = get_license_info()
|
|
242
|
+
gpu_hours_used = usage["gpu_seconds"] / 3600
|
|
243
|
+
gpu_hours_limit = info["limits"]["gpu_hours_month"]
|
|
244
|
+
|
|
245
|
+
if gpu_hours_used > gpu_hours_limit:
|
|
246
|
+
tier = info["tier"]
|
|
247
|
+
if tier == "FREE":
|
|
248
|
+
raise UsageLimitError(
|
|
249
|
+
f"Free tier limit exceeded ({gpu_hours_limit} GPU-hours/month). "
|
|
250
|
+
f"Upgrade at quarterbit.dev for unlimited usage."
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def report_usage():
|
|
255
|
+
"""Report usage to server (called periodically)."""
|
|
256
|
+
license_data = _load_license()
|
|
257
|
+
if not license_data:
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
usage = _load_usage()
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
req_data = json.dumps({
|
|
264
|
+
"licenseKey": license_data.get("key"),
|
|
265
|
+
"machineId": _get_machine_id(),
|
|
266
|
+
"gpuSeconds": usage.get("gpu_seconds", 0),
|
|
267
|
+
"sessionCount": len(usage.get("sessions", [])),
|
|
268
|
+
"month": usage.get("month"),
|
|
269
|
+
}).encode()
|
|
270
|
+
|
|
271
|
+
req = urllib.request.Request(
|
|
272
|
+
f"{LICENSE_API}/reportUsage",
|
|
273
|
+
data=req_data,
|
|
274
|
+
headers={"Content-Type": "application/json"},
|
|
275
|
+
method="POST"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
279
|
+
pass # Fire and forget
|
|
280
|
+
except:
|
|
281
|
+
pass # Silent fail - usage reporting is best-effort
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class LicenseError(Exception):
|
|
285
|
+
"""License validation error."""
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class UsageLimitError(Exception):
|
|
290
|
+
"""Usage limit exceeded."""
|
|
291
|
+
pass
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
# CLI interface
|
|
295
|
+
def main():
|
|
296
|
+
"""CLI entry point for license management."""
|
|
297
|
+
import sys
|
|
298
|
+
|
|
299
|
+
if len(sys.argv) < 2:
|
|
300
|
+
print("QuarterBit License Manager")
|
|
301
|
+
print("=" * 40)
|
|
302
|
+
info = get_license_info()
|
|
303
|
+
print(f"Tier: {info['tier']}")
|
|
304
|
+
print(f"Activated: {info['activated']}")
|
|
305
|
+
if info['activated']:
|
|
306
|
+
print(f"Email: {info.get('email', 'N/A')}")
|
|
307
|
+
print(f"Key: {info.get('key', 'N/A')}")
|
|
308
|
+
print(f"\nUsage this month:")
|
|
309
|
+
print(f" GPU hours: {info['usage']['gpu_hours_used']:.2f} / {info['usage']['gpu_hours_limit']}")
|
|
310
|
+
print(f"\nCommands:")
|
|
311
|
+
print(" quarterbit activate <KEY> - Activate license")
|
|
312
|
+
print(" quarterbit deactivate - Remove license")
|
|
313
|
+
print(" quarterbit status - Show this info")
|
|
314
|
+
return
|
|
315
|
+
|
|
316
|
+
cmd = sys.argv[1].lower()
|
|
317
|
+
|
|
318
|
+
if cmd == "activate":
|
|
319
|
+
if len(sys.argv) < 3:
|
|
320
|
+
print("Usage: quarterbit activate <LICENSE_KEY>")
|
|
321
|
+
sys.exit(1)
|
|
322
|
+
key = sys.argv[2]
|
|
323
|
+
try:
|
|
324
|
+
result = activate(key)
|
|
325
|
+
print(f"Success! {result['message']}")
|
|
326
|
+
except ValueError as e:
|
|
327
|
+
print(f"Error: {e}")
|
|
328
|
+
sys.exit(1)
|
|
329
|
+
|
|
330
|
+
elif cmd == "deactivate":
|
|
331
|
+
deactivate()
|
|
332
|
+
print("License deactivated.")
|
|
333
|
+
|
|
334
|
+
elif cmd == "status":
|
|
335
|
+
info = get_license_info()
|
|
336
|
+
print(f"Tier: {info['tier']}")
|
|
337
|
+
print(f"Activated: {info['activated']}")
|
|
338
|
+
if info['activated']:
|
|
339
|
+
print(f"Email: {info.get('email', 'N/A')}")
|
|
340
|
+
print(f"GPU hours used: {info['usage']['gpu_hours_used']:.2f} / {info['usage']['gpu_hours_limit']}")
|
|
341
|
+
|
|
342
|
+
else:
|
|
343
|
+
print(f"Unknown command: {cmd}")
|
|
344
|
+
sys.exit(1)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
if __name__ == "__main__":
|
|
348
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quarterbit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Precision optimizer for PyTorch - 1,000,000x more accurate than FP32
|
|
5
5
|
Author-email: Kyle Clouthier <info@quarterbit.dev>
|
|
6
6
|
License: Proprietary - Free tier available, commercial use requires license
|
|
@@ -2,9 +2,11 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
quarterbit/__init__.py
|
|
5
|
+
quarterbit/license.py
|
|
5
6
|
quarterbit.egg-info/PKG-INFO
|
|
6
7
|
quarterbit.egg-info/SOURCES.txt
|
|
7
8
|
quarterbit.egg-info/dependency_links.txt
|
|
9
|
+
quarterbit.egg-info/entry_points.txt
|
|
8
10
|
quarterbit.egg-info/requires.txt
|
|
9
11
|
quarterbit.egg-info/top_level.txt
|
|
10
12
|
quarterbit/torch/__init__.py
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
QuarterBit
|
|
3
|
-
==========
|
|
4
|
-
|
|
5
|
-
Precision computing library.
|
|
6
|
-
|
|
7
|
-
Usage:
|
|
8
|
-
from quarterbit.torch import Adam
|
|
9
|
-
|
|
10
|
-
Copyright (c) 2026 Clouthier Simulation Labs. All rights reserved.
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
__version__ = "1.0.0"
|
|
14
|
-
__author__ = "Kyle Clouthier"
|
|
15
|
-
__license__ = "Proprietary"
|
|
16
|
-
|
|
17
|
-
import os as _os
|
|
18
|
-
import hashlib as _hashlib
|
|
19
|
-
import platform as _platform
|
|
20
|
-
|
|
21
|
-
# ============================================================================
|
|
22
|
-
# License Validation (stub - implement full validation later)
|
|
23
|
-
# ============================================================================
|
|
24
|
-
|
|
25
|
-
_LICENSE_KEY = _os.environ.get("QUARTERBIT_LICENSE_KEY", "")
|
|
26
|
-
_VALIDATED = False
|
|
27
|
-
|
|
28
|
-
def _validate_license():
|
|
29
|
-
"""Validate license key. Returns tier or raises."""
|
|
30
|
-
global _VALIDATED
|
|
31
|
-
|
|
32
|
-
if _VALIDATED:
|
|
33
|
-
return True
|
|
34
|
-
|
|
35
|
-
# Free tier: limited functionality
|
|
36
|
-
if not _LICENSE_KEY:
|
|
37
|
-
_VALIDATED = True
|
|
38
|
-
return "free"
|
|
39
|
-
|
|
40
|
-
# TODO: Implement full license validation against server
|
|
41
|
-
# For now, any key = pro tier
|
|
42
|
-
_VALIDATED = True
|
|
43
|
-
return "pro"
|
|
44
|
-
|
|
45
|
-
def _check_environment():
|
|
46
|
-
"""Check for debugging/reverse engineering attempts."""
|
|
47
|
-
# Basic anti-debug checks
|
|
48
|
-
suspicious = []
|
|
49
|
-
|
|
50
|
-
# Check for common debuggers
|
|
51
|
-
if _os.environ.get("PYTHONDEBUG"):
|
|
52
|
-
suspicious.append("debug_mode")
|
|
53
|
-
|
|
54
|
-
# Check for trace
|
|
55
|
-
import sys
|
|
56
|
-
if sys.gettrace() is not None:
|
|
57
|
-
suspicious.append("trace_active")
|
|
58
|
-
|
|
59
|
-
return suspicious
|
|
60
|
-
|
|
61
|
-
# Run checks on import
|
|
62
|
-
_tier = _validate_license()
|
|
63
|
-
_suspicious = _check_environment()
|
|
64
|
-
|
|
65
|
-
if _suspicious and _tier == "free":
|
|
66
|
-
import warnings
|
|
67
|
-
warnings.warn("QuarterBit: Debug mode detected. Some features disabled.")
|
|
68
|
-
|
|
69
|
-
# ============================================================================
|
|
70
|
-
# Public API
|
|
71
|
-
# ============================================================================
|
|
72
|
-
|
|
73
|
-
def get_version():
|
|
74
|
-
"""Get QuarterBit version."""
|
|
75
|
-
return __version__
|
|
76
|
-
|
|
77
|
-
def get_license_tier():
|
|
78
|
-
"""Get current license tier."""
|
|
79
|
-
return _tier
|
|
80
|
-
|
|
81
|
-
def is_available():
|
|
82
|
-
"""Check if QuarterBit GPU backend is available."""
|
|
83
|
-
try:
|
|
84
|
-
from .torch.utils import is_available as _gpu_available
|
|
85
|
-
return _gpu_available()
|
|
86
|
-
except ImportError:
|
|
87
|
-
return False
|
|
88
|
-
|
|
89
|
-
# Lazy imports for submodules
|
|
90
|
-
def __getattr__(name):
|
|
91
|
-
if name == "torch":
|
|
92
|
-
from . import torch
|
|
93
|
-
return torch
|
|
94
|
-
raise AttributeError(f"module 'quarterbit' has no attribute '{name}'")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|