Download rebuild_sources.py from nur-dev/unionmind-predictive-representations: direct link, hf CLI and curl.
- Browser
- Download file 5.11 kB
-
https://huggingface.co/nur-dev/unionmind-predictive-representations/resolve/main/rebuild_sources.py
- Command line
-
hf download hf://nur-dev/unionmind-predictive-representations/rebuild_sources.py
-
curl -L -o rebuild_sources.py https://huggingface.co/nur-dev/unionmind-predictive-representations/resolve/main/rebuild_sources.py
5.11 kB
| """Rebuild the two compositional feature archives from official raw recordings. | |
| Use --hydraulic-archive and --temperature-archive to reuse downloaded archives. | |
| Source scientific aggregation stays on CUDA. Raw archives are never republished. | |
| """ | |
| from pathlib import Path | |
| import argparse,hashlib,io,itertools,json,urllib.request,zipfile | |
| import numpy as np | |
| import torch | |
| from reproduce import ROOT,load | |
| def digest(p):return hashlib.sha256(Path(p).read_bytes()).hexdigest() | |
| def acquire(path,url,expected): | |
| path=Path(path) | |
| if not path.exists():path.parent.mkdir(parents=True,exist_ok=True);urllib.request.urlretrieve(url,path) | |
| assert digest(path)==expected,('archive hash mismatch',path) | |
| return path | |
| def hydraulic(path,device): | |
| from unionmind.continuous_decision import source | |
| import tempfile,os | |
| config=json.loads((ROOT/'protocols/factorial_transfer_protocol_01.json').read_text()) | |
| with tempfile.TemporaryDirectory(prefix='hydraulic-rebuild-') as tmp: | |
| tmp=Path(tmp);(tmp/'sources').mkdir();os.symlink(Path(path).resolve(),tmp/'sources/hydraulic.zip') | |
| source.prepare_hydraulic(tmp,config,device) | |
| rebuilt=torch.load(tmp/'prepared/hydraulic.pt',map_location=device,weights_only=True) | |
| expected=load('data/hydraulic/prepared',device) | |
| assert torch.allclose(rebuilt['x'],expected['x'],atol=1e-10,rtol=1e-12) | |
| assert torch.equal(rebuilt['h'],expected['h']) | |
| for k in expected['masks']:assert torch.equal(expected['masks'][k],rebuilt['masks'][k]) | |
| return dict(records=len(rebuilt['x']),maximum_feature_error=float((rebuilt['x']-expected['x']).abs().max()),split_masks_identical=True) | |
| def temperature(path,device): | |
| rows=[];labels=[];days=[];invalid=[] | |
| with zipfile.ZipFile(path) as outer: | |
| inner=zipfile.ZipFile(io.BytesIO(outer.read('gas-sensor-array-temperature-modulation.zip'))) | |
| members=sorted(a.filename for a in inner.infolist() if a.filename.endswith('.csv')) | |
| assert len(members)==13 | |
| for day,name in enumerate(members): | |
| data=np.loadtxt(io.BytesIO(inner.read(name)),delimiter=',',skiprows=1) | |
| raw=torch.as_tensor(data,device=device,dtype=torch.float64);t=raw[:,0] | |
| if not bool(torch.isfinite(raw).all()) or not bool((torch.diff(t)>=0).all()):invalid.append(name);continue | |
| for block in range(int(torch.floor((t[-1]-t[0])/900))+1): | |
| boundary=t[0]+torch.arange(5,device=device,dtype=torch.float64)*225+block*900 | |
| ix=torch.searchsorted(t,boundary);a,b=int(ix[0]),min(int(ix[-1]),len(t)) | |
| if b<=a or float(t[b-1]-t[a])<850:continue | |
| q=torch.stack([raw[int(ix[k]):int(ix[k+1]),6:20].mean(0) for k in range(4)]) | |
| last=raw[int(ix[3]):b];co=torch.quantile(last[:,1],.5,interpolation='lower');rh=last[:,2].mean() | |
| levels=torch.linspace(0,20,10,device=device,dtype=torch.float64) | |
| rows.append(q.T.reshape(-1));labels.append(torch.stack(((levels-co).abs().argmin(),torch.bucketize(rh,rh.new_tensor([35.,55.])))));days.append(day) | |
| x=torch.stack(rows);h=torch.stack(labels);d=torch.tensor(days,device=device) | |
| grid=list(itertools.product(range(10),range(3)));held=sorted(grid,key=lambda v:hashlib.sha256(f'20821:{v[0]},{v[1]}'.encode()).hexdigest())[:6] | |
| unseen=torch.zeros(len(x),device=device,dtype=torch.bool) | |
| for binding in held:unseen|=(h==h.new_tensor(binding)).all(1) | |
| rebuilt=dict(x=x,h=h,days=d,source=(d<9)&~unseen,target=d>=9,unseen=unseen);expected=load('data/temperature/prepared',device) | |
| for k in expected: | |
| if k=='x':assert torch.allclose(rebuilt[k],expected[k],atol=1e-10,rtol=1e-12) | |
| else:assert torch.equal(rebuilt[k],expected[k]),k | |
| assert len(invalid)==1 and '20161003_085624.csv' in invalid[0] | |
| return dict(records=len(x),maximum_feature_error=float((x-expected['x']).abs().max()),invalid_days=invalid,original_primary_eligibility=False,secondary_split_identical=True) | |
| def main(): | |
| p=argparse.ArgumentParser(description=__doc__);p.add_argument('--device',default='cuda:0');p.add_argument('--cache',default='raw_downloads');p.add_argument('--hydraulic-archive');p.add_argument('--temperature-archive');p.add_argument('--output',default='raw_rebuild.json');a=p.parse_args() | |
| assert a.device.startswith('cuda') and torch.cuda.is_available();torch.cuda.set_device(a.device);torch.backends.cuda.matmul.allow_tf32=False | |
| cache=Path(a.cache);hyd=acquire(a.hydraulic_archive or cache/'hydraulic.zip','https://archive.ics.uci.edu/static/public/447/condition+monitoring+of+hydraulic+systems.zip','24128aad2ee45eea7e6b63ebbd9992cdf25d0483a2cebefbfc13bc69079af1f2') | |
| tmp=acquire(a.temperature_archive or cache/'temperature.zip','https://archive.ics.uci.edu/static/public/487/gas+sensor+array+temperature+modulation.zip','cb5ce4a6af1a51b933d1979952d7845f0e9baac54e15a81a1e3599e8b85905d4') | |
| report={'hydraulic':hydraulic(hyd,a.device),'temperature':temperature(tmp,a.device)};Path(a.output).write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report,indent=2)) | |
| if __name__=='__main__':main() | |