morphtree 2.1.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. morphtree/__init__.py +28 -0
  2. morphtree/__main__.py +3 -0
  3. morphtree/_experimental/__init__.py +1 -0
  4. morphtree/_experimental/admission.py +364 -0
  5. morphtree/_experimental/base.py +215 -0
  6. morphtree/_experimental/component_cache_v2.py +263 -0
  7. morphtree/_experimental/evolution_report.py +307 -0
  8. morphtree/_experimental/execution_v2.py +697 -0
  9. morphtree/_experimental/facade.py +289 -0
  10. morphtree/_experimental/integrated.py +748 -0
  11. morphtree/_experimental/learning.py +418 -0
  12. morphtree/_experimental/manifest.json +204 -0
  13. morphtree/_experimental/numeric_fixture.py +21 -0
  14. morphtree/_experimental/parameter_contract.py +38 -0
  15. morphtree/_experimental/postfit.py +51 -0
  16. morphtree/_experimental/preprocessing.py +133 -0
  17. morphtree/_experimental/processes.py +191 -0
  18. morphtree/_experimental/producer.py +542 -0
  19. morphtree/_experimental/product.py +156 -0
  20. morphtree/_experimental/product_cli.py +43 -0
  21. morphtree/_experimental/roundtrip_v3.py +311 -0
  22. morphtree/_experimental/runtime_io.py +65 -0
  23. morphtree/_experimental/sampling.py +26 -0
  24. morphtree/_experimental/support.py +281 -0
  25. morphtree/_experimental/target.py +59 -0
  26. morphtree/_experimental/training.py +53 -0
  27. morphtree/_experimental/worker.py +682 -0
  28. morphtree/_installed.py +17 -0
  29. morphtree/_native/__init__.py +1 -0
  30. morphtree/_native/bin/win_amd64/morphtree_kernels.dll +0 -0
  31. morphtree/_native/buffers.py +82 -0
  32. morphtree/_native/loader.py +39 -0
  33. morphtree/_native/manifest.json +29 -0
  34. morphtree/_native/runtime.py +48 -0
  35. morphtree/_native/src/histogram.c +61 -0
  36. morphtree/_native/src/traversal.c +51 -0
  37. morphtree/api.py +388 -0
  38. morphtree/api_compat.py +65 -0
  39. morphtree/backend.py +162 -0
  40. morphtree/booster.py +252 -0
  41. morphtree/cli.py +52 -0
  42. morphtree/config.py +262 -0
  43. morphtree/control.py +20 -0
  44. morphtree/data.py +300 -0
  45. morphtree/diagnostics.py +158 -0
  46. morphtree/estimators.py +156 -0
  47. morphtree/examples.py +25 -0
  48. morphtree/exporting.py +224 -0
  49. morphtree/legacy_artifacts.py +32 -0
  50. morphtree/metrics.py +156 -0
  51. morphtree/model.py +1010 -0
  52. morphtree/mutations.py +205 -0
  53. morphtree/native_lab_backend.py +79 -0
  54. morphtree/numpy_backend.py +180 -0
  55. morphtree/optuna_tuner.py +154 -0
  56. morphtree/persistence.py +414 -0
  57. morphtree/prediction_output.py +35 -0
  58. morphtree/prepared_bins.py +82 -0
  59. morphtree/public.py +106 -0
  60. morphtree/resource_plan.py +170 -0
  61. morphtree/scalable.py +781 -0
  62. morphtree/scalable_backend.py +74 -0
  63. morphtree/scalable_checkpoint.py +129 -0
  64. morphtree/scalable_data.py +255 -0
  65. morphtree/scalable_receipts.py +92 -0
  66. morphtree/scalable_target.py +68 -0
  67. morphtree/scalable_variants.py +133 -0
  68. morphtree/sklearn_view.py +79 -0
  69. morphtree/source_markers.py +25 -0
  70. morphtree/species.py +47 -0
  71. morphtree/temporary.py +65 -0
  72. morphtree/training_fragment.py +130 -0
  73. morphtree/tree.py +231 -0
  74. morphtree/tuning.py +150 -0
  75. morphtree-2.1.0.dist-info/METADATA +212 -0
  76. morphtree-2.1.0.dist-info/RECORD +79 -0
  77. morphtree-2.1.0.dist-info/WHEEL +4 -0
  78. morphtree-2.1.0.dist-info/entry_points.txt +2 -0
  79. morphtree-2.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,170 @@
1
+ """Finite workload-based allowances, not dataset size admission thresholds.
2
+
3
+ Coefficients are conservative engineering heuristics, not a completion-time or
4
+ RSS theorem. Explicit user allowances always win. No target values, scores or
5
+ EXTERNAL data enter the plan; no samples or evolutionary stages are removed.
6
+ """
7
+ import math
8
+
9
+
10
+ def memory_snapshot(host_available):
11
+ """Read-only OS limits, without changing a job/cgroup or foreign process.
12
+
13
+ Windows scope is the immediate job plus an optional supervisor-verified
14
+ process ceiling. Numeric context never holds a job handle, which would keep
15
+ a kill-on-last-handle-close cleanup job alive after its owner died.
16
+ Linux scope is the visible cgroup hierarchy and RLIMIT_AS. Unsupported or
17
+ unreadable limits are reported, never claimed as fully qualified coverage.
18
+ """
19
+ import os
20
+ constraints=[];unavailable=[];private=None
21
+ if os.name=='nt':
22
+ import ctypes
23
+ from ctypes import wintypes as w
24
+ class Basic(ctypes.Structure):
25
+ _fields_=[('process_time',ctypes.c_int64),('job_time',ctypes.c_int64),('flags',w.DWORD),('min_ws',ctypes.c_size_t),('max_ws',ctypes.c_size_t),('active',w.DWORD),('affinity',ctypes.c_size_t),('priority',w.DWORD),('scheduling',w.DWORD)]
26
+ class IO(ctypes.Structure):_fields_=[(n,ctypes.c_uint64) for n in ('ro','wo','oo','rb','wb','ob')]
27
+ class Extended(ctypes.Structure):_fields_=[('basic',Basic),('io',IO),('process_limit',ctypes.c_size_t),('job_limit',ctypes.c_size_t),('process_peak',ctypes.c_size_t),('job_peak',ctypes.c_size_t)]
28
+ class Usage(ctypes.Structure):_fields_=[('current',ctypes.c_uint64),('peak',ctypes.c_uint64)]
29
+ class Process(ctypes.Structure):_fields_=[('size',w.DWORD),('faults',w.DWORD)]+[(n,ctypes.c_size_t) for n in ('peak_ws','ws','peak_paged','paged','peak_nonpaged','nonpaged','pagefile','peak_pagefile','private')]
30
+ kernel=ctypes.WinDLL('kernel32',use_last_error=True);psapi=ctypes.WinDLL('psapi',use_last_error=True)
31
+ kernel.QueryInformationJobObject.argtypes=[w.HANDLE,ctypes.c_int,ctypes.c_void_p,w.DWORD,ctypes.c_void_p]
32
+ psapi.GetProcessMemoryInfo.argtypes=[w.HANDLE,ctypes.c_void_p,w.DWORD]
33
+ current_process=Process();current_process.size=ctypes.sizeof(current_process)
34
+ if psapi.GetProcessMemoryInfo(ctypes.c_void_p(-1),ctypes.byref(current_process),current_process.size):private=current_process.private
35
+ else:unavailable.append('Windows_process_commit_usage')
36
+ for handle,scope in [(None,'immediate')]:
37
+ limits=Extended()
38
+ if kernel.QueryInformationJobObject(handle,9,ctypes.byref(limits),ctypes.sizeof(limits),None):
39
+ if limits.basic.flags&0x100:
40
+ if private is not None:constraints.append(dict(kind='Windows_process_commit',job_scope=scope,limit=limits.process_limit,current=private))
41
+ else:unavailable.append(scope+'_process_commit_usage')
42
+ if limits.basic.flags&0x200:
43
+ current=Usage()
44
+ if kernel.QueryInformationJobObject(handle,28,ctypes.byref(current),ctypes.sizeof(current),None):constraints.append(dict(kind='Windows_job_commit',job_scope=scope,limit=limits.job_limit,current=current.current))
45
+ else:unavailable.append(scope+'_job_current_usage')
46
+ else:unavailable.append(scope+'_job_unavailable')
47
+ declared=getattr(memory_snapshot,'_supervised_process_limit',None)
48
+ if declared is not None:
49
+ if type(declared) is not int or declared<1:raise ValueError('Positive supervisor-verified process ceiling')
50
+ if private is None:raise MemoryError('Cannot measure process commit under supervisor ceiling')
51
+ constraints.append(dict(kind='Windows_process_commit',job_scope='supervisor_verified_policy',limit=declared,current=private))
52
+ unavailable.append('Other_Windows_ancestor_jobs_not_enumerated')
53
+ elif os.name=='posix':
54
+ from pathlib import Path
55
+ try:
56
+ entries=Path('/proc/self/cgroup').read_text('ascii').splitlines()
57
+ for entry in entries:
58
+ hierarchy,controllers,relative=entry.split(':',2)
59
+ if hierarchy=='0' and not controllers:base=Path('/sys/fs/cgroup');names=('memory.max','memory.current')
60
+ elif 'memory' in controllers.split(','):base=Path('/sys/fs/cgroup/memory');names=('memory.limit_in_bytes','memory.usage_in_bytes')
61
+ else:continue
62
+ current=(base/relative.lstrip('/')).resolve()
63
+ if not current.is_relative_to(base):raise ValueError('Unsafe cgroup path')
64
+ for parent in (current,*current.parents):
65
+ if not parent.is_relative_to(base):break
66
+ if not (parent/names[0]).exists():continue
67
+ maximum=(parent/names[0]).read_text('ascii').strip()
68
+ if maximum!='max':constraints.append(dict(kind='Linux_visible_cgroup',limit=int(maximum),current=int((parent/names[1]).read_text('ascii').strip())))
69
+ except (OSError,ValueError):unavailable.append('Linux_cgroup_limits')
70
+ try:
71
+ import resource
72
+ limit=resource.getrlimit(resource.RLIMIT_AS)[0]
73
+ if limit!=resource.RLIM_INFINITY:
74
+ status=Path('/proc/self/status').read_text('ascii');virtual=next(int(line.split()[1])*1024 for line in status.splitlines() if line.startswith('VmSize:'))
75
+ constraints.append(dict(kind='POSIX_address_space',limit=limit,current=virtual))
76
+ except (OSError,ValueError,StopIteration,ImportError):unavailable.append('POSIX_address_space_limit')
77
+ for c in constraints:c['remaining']=max(0,c['limit']-c['current'])
78
+ effective=min([host_available]+[c['remaining'] for c in constraints])
79
+ return dict(host_available_bytes=host_available,effective_available_bytes=effective,process_private_bytes=private,constraints=constraints,unavailable=unavailable,scope='Visible limits plus optional externally verified process ceiling; unknown ancestors remain explicit. Commit/address-space and RAM are distinct,not a portable hardRSS proof')
80
+
81
+
82
+ def memory_allowance(requested,available):
83
+ if type(available) is not int or available<0:raise ValueError('Nonnegative available memory observation')
84
+ if not available:raise MemoryError('No available RAM/commit/address-space headroom')
85
+ if requested=='auto':return max(1,available//2)
86
+ if type(requested) is not int or requested<1:raise ValueError('Positive byte allowance or auto')
87
+ return min(requested,available)
88
+
89
+
90
+ def fit_plan(rows,features,classes,params,mutations,trials,refit,available,time_budget,memory_budget):
91
+ if any(type(v) is not int or v<1 for v in (rows,features,classes)):raise ValueError('Positive shape/class dimensions')
92
+ m=params.n_estimators
93
+ # Worst of the two families; fresh diagnosis after every accepted parent.
94
+ # OOF consists of two half-TRAIN fits per member, never a new size sample.
95
+ native=1+m*(1+3*mutations+trials+int(refit))
96
+ scalar_classes=classes if classes>2 else 1
97
+ scalar=m*(2+3*mutations+trials+int(refit))*scalar_classes
98
+ row_passes=m*((2+2*mutations+trials)*.75*rows+int(refit)*rows)*scalar_classes
99
+ depth=min(params.max_depth,params.max_leaves-1)
100
+ tree_work=row_passes*features*depth
101
+ # Conservative sorting envelope even when bounded prepared bins hit.
102
+ sorting_work=rows*features*math.log2(max(2,rows))*native
103
+ try:automatic=max(150.,30.+tree_work/750000.+sorting_work/40000000.)
104
+ except OverflowError:raise ValueError('Workload outside finite Python time representation') from None
105
+ seconds=automatic if time_budget=='auto' else float(time_budget)
106
+ if not math.isfinite(seconds) or seconds<=0:raise ValueError('Positive finite time allowance')
107
+ memory=memory_allowance(memory_budget,available);cache=min(32*1024**2,memory//8)
108
+ minimum=rows*features*10+rows*(256+80*classes)+features*512+cache+scalar*(2*params.max_leaves-1)*1024
109
+ return dict(schema='SCALABLE_RESOURCE_PLAN_1',rows=rows,features=features,classes=classes,
110
+ memory_mode='auto' if memory_budget=='auto' else 'explicit',available_bytes=available,
111
+ memory_bytes=memory,estimated_workspace_bytes=minimum,prepared_cache_bytes=cache,
112
+ time_mode='auto' if time_budget=='auto' else 'explicit',seconds=seconds,
113
+ estimated_native_fit_ceiling=native,estimated_scalar_tree_ceiling=scalar,
114
+ scalar_row_passes=row_passes,tree_work_units=tree_work,sort_work_units=sorting_work,
115
+ automatic_seconds=automatic,seconds_floor=150.,tree_units_per_second=750000.,sort_units_per_second=40000000.,
116
+ guarantee='Heuristic forecast plus observed resource checks; not a hard peak or completion guarantee')
117
+
118
+
119
+ def inference_seconds(rows,features,scalar_trees,depth):
120
+ try:seconds=max(150.,30.+rows*(features+scalar_trees*depth)/750000.)
121
+ except OverflowError:raise ValueError('Inference workload outside finite time representation') from None
122
+ if not math.isfinite(seconds):raise ValueError('Finite inference workload required')
123
+ return seconds
124
+
125
+
126
+ def io_seconds(nbytes):return max(150.,nbytes/(1024**2))
127
+
128
+
129
+ def numeric_capacity_plan(plan,params,mutations,trials,refit,explicit_estimators):
130
+ """Derive a finite final numeric domain without using any model score.
131
+
132
+ Initial screening and structural evolution keep their original capacity.
133
+ At most45percent of the initial configured time allowance funds final
134
+ numeric candidates/refit. Rates are the existing conservative work model,
135
+ not measured host speed; seeds/shape/explicit allowances are reproducible.
136
+ Memory includes retained candidate models.4096 is the existing HyperParams
137
+ numerical contract,not an admission limit on input observations/features.
138
+ """
139
+ result=dict(plan);base=params.n_estimators;k=plan['classes'] if plan['classes']>2 else 1;n=plan['rows'];f=plan['features'];depth=min(params.max_depth,params.max_leaves-1)
140
+ per_seconds=n*f*depth*k*(.75*trials+int(refit))/plan['tree_units_per_second']+n*f*math.log2(max(2,n))*(trials+int(refit))/plan['sort_units_per_second']
141
+ per_bytes=(trials+int(refit))*((2*params.max_leaves-1)*1024*k+f*params.max_bins*64)
142
+ maximum=base;reason='Explicit estimator capacity' if explicit_estimators else 'Numeric tuning disabled'
143
+ if trials and not explicit_estimators:
144
+ time_max=max(base,math.floor(.45*plan['seconds']/max(1e-12,per_seconds)))
145
+ memory_max=base+max(0,plan['memory_bytes']-plan['estimated_workspace_bytes'])//max(1,per_bytes)
146
+ maximum=max(base,min(4096,time_max,memory_max));reason='Input shape and configured time/memory allowances only'
147
+ result['numeric_capacity']=dict(minimum_estimators=base,maximum_estimators=maximum,reason=reason,score_or_target_values_used=False,time_fraction=.45,seconds_per_estimator_all_numeric_and_refit=per_seconds,bytes_per_additional_estimator_all_candidates=per_bytes)
148
+ result['estimated_native_fit_ceiling']=1+base*(1+3*mutations)+(trials+int(refit))*maximum
149
+ result['estimated_scalar_tree_ceiling']=(base*(2+3*mutations)+(trials+int(refit))*maximum)*k
150
+ result['estimated_workspace_bytes']+=(maximum-base)*per_bytes
151
+ result['scalar_row_passes']=(base*(2+2*mutations)*.75*n+maximum*(.75*trials+int(refit))*n)*k
152
+ result['tree_work_units']=result['scalar_row_passes']*f*depth
153
+ result['sort_work_units']=n*f*math.log2(max(2,n))*result['estimated_native_fit_ceiling']
154
+ result['expanded_work_forecast_seconds']=max(150.,30.+result['tree_work_units']/plan['tree_units_per_second']+result['sort_work_units']/plan['sort_units_per_second'])
155
+ # The selected numerical domain is fixed above. Do not recalculate it
156
+ # from an extended deadline:that would create a capacity/time feedback loop.
157
+ # Auto time must cover the work envelope it selected;explicit deadlines
158
+ # remain exact caller policy and can still stop a best-effort fit early.
159
+ initial_seconds=result['seconds']
160
+ extension=0.
161
+ if plan.get('time_mode')=='auto' and maximum>base:
162
+ extension=max(0.,result['expanded_work_forecast_seconds']-initial_seconds)
163
+ if extension:
164
+ result['seconds']=result['expanded_work_forecast_seconds']
165
+ result['automatic_seconds']=result['seconds']
166
+ result['numeric_capacity']['initial_time_allowance_seconds']=initial_seconds
167
+ result['numeric_capacity']['automatic_deadline_extension_seconds']=extension
168
+ result['numeric_capacity']['domain_recomputed_after_extension']=False
169
+ result['numeric_capacity']['forecast_within_configured_time']=result['expanded_work_forecast_seconds']<=result['seconds'] or math.isclose(result['expanded_work_forecast_seconds'],result['seconds'],rel_tol=1e-12,abs_tol=1e-12)
170
+ return result