diff --git a/examples/baremetal/README.md b/examples/baremetal/README.md index f3f3f3fe..00884311 100644 --- a/examples/baremetal/README.md +++ b/examples/baremetal/README.md @@ -8,7 +8,11 @@ There is no attempt to prioritize jobs: it is just FIFO. The main function is ju Each job consumes one GPU, as key a simplification to minimize resource management complexity. -## Environment variables +## State and config files + +The baremetal program itself uses a `config.html` file for configuration, and saves a record of all jobs and active state in a `state.json` file, both of which are saved in the "app data" location for the app (e.g., `~/Library/BareMetal` on mac). The state file allows the baremetal program to be fully restartable. + +## Environment variables for running job * `BARE_GPU` = the allocated GPU number (0..N] @@ -22,6 +26,10 @@ Each job consumes one GPU, as key a simplification to minimize resource manageme ## Configuring a new "bare metal" linux compute server ```sh -sudo apt install golang gcc libgl1-mesa-dev libegl1-mesa-dev mesa-vulkan-drivers xorg-dev vulkan-tools nvidia-driver-565-server nvidia-utils-565-server +sudo apt install gcc libgl1-mesa-dev libegl1-mesa-dev mesa-vulkan-drivers xorg-dev vulkan-tools nvidia-driver-550-server nvidia-utils-550-server ``` +Note: the nvidia-* packages are critical for vulkaninfo to see the GPUs. No additional DISPLAY variable or anything should be necessary. 550 is the stable branch (recommended) while 565 is a more advanced "new features" branch. + +Typically have to install Go manually from https://go.dev/doc/install to get an up-to-date version. + diff --git a/examples/baremetal/baremetal/baremetal.pb.go b/examples/baremetal/baremetal/baremetal.pb.go index 0816be7a..665f1aa3 100644 --- a/examples/baremetal/baremetal/baremetal.pb.go +++ b/examples/baremetal/baremetal/baremetal.pb.go @@ -538,14 +538,14 @@ var file_baremetal_baremetal_proto_rawDesc = []byte{ 0x72, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x6c, 0x12, 0x2f, 0x0a, 0x06, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x15, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x0e, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, - 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x12, 0x34, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x14, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, - 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x62, - 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x35, - 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x2e, 0x62, 0x61, - 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x4c, 0x69, 0x73, - 0x74, 0x1a, 0x12, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, - 0x62, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, + 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x12, 0x35, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, + 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x62, 0x61, + 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x34, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x14, 0x2e, + 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x4c, + 0x69, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x38, 0x0a, 0x0c, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x14, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x12, @@ -590,13 +590,13 @@ var file_baremetal_baremetal_proto_depIdxs = []int32{ 6, // 3: baremetal.Job.end:type_name -> google.protobuf.Timestamp 2, // 4: baremetal.JobList.jobs:type_name -> baremetal.Job 1, // 5: baremetal.BareMetal.Submit:input_type -> baremetal.Submission - 4, // 6: baremetal.BareMetal.CancelJobs:input_type -> baremetal.JobIDList - 4, // 7: baremetal.BareMetal.JobStatus:input_type -> baremetal.JobIDList + 4, // 6: baremetal.BareMetal.JobStatus:input_type -> baremetal.JobIDList + 4, // 7: baremetal.BareMetal.CancelJobs:input_type -> baremetal.JobIDList 4, // 8: baremetal.BareMetal.FetchResults:input_type -> baremetal.JobIDList 7, // 9: baremetal.BareMetal.UpdateJobs:input_type -> google.protobuf.Empty 2, // 10: baremetal.BareMetal.Submit:output_type -> baremetal.Job - 5, // 11: baremetal.BareMetal.CancelJobs:output_type -> baremetal.Error - 3, // 12: baremetal.BareMetal.JobStatus:output_type -> baremetal.JobList + 3, // 11: baremetal.BareMetal.JobStatus:output_type -> baremetal.JobList + 5, // 12: baremetal.BareMetal.CancelJobs:output_type -> baremetal.Error 3, // 13: baremetal.BareMetal.FetchResults:output_type -> baremetal.JobList 7, // 14: baremetal.BareMetal.UpdateJobs:output_type -> google.protobuf.Empty 10, // [10:15] is the sub-list for method output_type diff --git a/examples/baremetal/baremetal/baremetal_grpc.pb.go b/examples/baremetal/baremetal/baremetal_grpc.pb.go index 98634793..2765164c 100644 --- a/examples/baremetal/baremetal/baremetal_grpc.pb.go +++ b/examples/baremetal/baremetal/baremetal_grpc.pb.go @@ -21,8 +21,8 @@ const _ = grpc.SupportPackageIsVersion9 const ( BareMetal_Submit_FullMethodName = "/baremetal.BareMetal/Submit" - BareMetal_CancelJobs_FullMethodName = "/baremetal.BareMetal/CancelJobs" BareMetal_JobStatus_FullMethodName = "/baremetal.BareMetal/JobStatus" + BareMetal_CancelJobs_FullMethodName = "/baremetal.BareMetal/CancelJobs" BareMetal_FetchResults_FullMethodName = "/baremetal.BareMetal/FetchResults" BareMetal_UpdateJobs_FullMethodName = "/baremetal.BareMetal/UpdateJobs" ) @@ -32,8 +32,8 @@ const ( // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type BareMetalClient interface { Submit(ctx context.Context, in *Submission, opts ...grpc.CallOption) (*Job, error) - CancelJobs(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*Error, error) JobStatus(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*JobList, error) + CancelJobs(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*Error, error) FetchResults(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*JobList, error) UpdateJobs(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) } @@ -56,20 +56,20 @@ func (c *bareMetalClient) Submit(ctx context.Context, in *Submission, opts ...gr return out, nil } -func (c *bareMetalClient) CancelJobs(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*Error, error) { +func (c *bareMetalClient) JobStatus(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*JobList, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(Error) - err := c.cc.Invoke(ctx, BareMetal_CancelJobs_FullMethodName, in, out, cOpts...) + out := new(JobList) + err := c.cc.Invoke(ctx, BareMetal_JobStatus_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *bareMetalClient) JobStatus(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*JobList, error) { +func (c *bareMetalClient) CancelJobs(ctx context.Context, in *JobIDList, opts ...grpc.CallOption) (*Error, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(JobList) - err := c.cc.Invoke(ctx, BareMetal_JobStatus_FullMethodName, in, out, cOpts...) + out := new(Error) + err := c.cc.Invoke(ctx, BareMetal_CancelJobs_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -101,8 +101,8 @@ func (c *bareMetalClient) UpdateJobs(ctx context.Context, in *emptypb.Empty, opt // for forward compatibility. type BareMetalServer interface { Submit(context.Context, *Submission) (*Job, error) - CancelJobs(context.Context, *JobIDList) (*Error, error) JobStatus(context.Context, *JobIDList) (*JobList, error) + CancelJobs(context.Context, *JobIDList) (*Error, error) FetchResults(context.Context, *JobIDList) (*JobList, error) UpdateJobs(context.Context, *emptypb.Empty) (*emptypb.Empty, error) mustEmbedUnimplementedBareMetalServer() @@ -118,12 +118,12 @@ type UnimplementedBareMetalServer struct{} func (UnimplementedBareMetalServer) Submit(context.Context, *Submission) (*Job, error) { return nil, status.Errorf(codes.Unimplemented, "method Submit not implemented") } -func (UnimplementedBareMetalServer) CancelJobs(context.Context, *JobIDList) (*Error, error) { - return nil, status.Errorf(codes.Unimplemented, "method CancelJobs not implemented") -} func (UnimplementedBareMetalServer) JobStatus(context.Context, *JobIDList) (*JobList, error) { return nil, status.Errorf(codes.Unimplemented, "method JobStatus not implemented") } +func (UnimplementedBareMetalServer) CancelJobs(context.Context, *JobIDList) (*Error, error) { + return nil, status.Errorf(codes.Unimplemented, "method CancelJobs not implemented") +} func (UnimplementedBareMetalServer) FetchResults(context.Context, *JobIDList) (*JobList, error) { return nil, status.Errorf(codes.Unimplemented, "method FetchResults not implemented") } @@ -169,38 +169,38 @@ func _BareMetal_Submit_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } -func _BareMetal_CancelJobs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _BareMetal_JobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(JobIDList) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(BareMetalServer).CancelJobs(ctx, in) + return srv.(BareMetalServer).JobStatus(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: BareMetal_CancelJobs_FullMethodName, + FullMethod: BareMetal_JobStatus_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BareMetalServer).CancelJobs(ctx, req.(*JobIDList)) + return srv.(BareMetalServer).JobStatus(ctx, req.(*JobIDList)) } return interceptor(ctx, in, info, handler) } -func _BareMetal_JobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _BareMetal_CancelJobs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(JobIDList) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(BareMetalServer).JobStatus(ctx, in) + return srv.(BareMetalServer).CancelJobs(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: BareMetal_JobStatus_FullMethodName, + FullMethod: BareMetal_CancelJobs_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BareMetalServer).JobStatus(ctx, req.(*JobIDList)) + return srv.(BareMetalServer).CancelJobs(ctx, req.(*JobIDList)) } return interceptor(ctx, in, info, handler) } @@ -252,14 +252,14 @@ var BareMetal_ServiceDesc = grpc.ServiceDesc{ MethodName: "Submit", Handler: _BareMetal_Submit_Handler, }, - { - MethodName: "CancelJobs", - Handler: _BareMetal_CancelJobs_Handler, - }, { MethodName: "JobStatus", Handler: _BareMetal_JobStatus_Handler, }, + { + MethodName: "CancelJobs", + Handler: _BareMetal_CancelJobs_Handler, + }, { MethodName: "FetchResults", Handler: _BareMetal_FetchResults_Handler, diff --git a/examples/baremetal/tar.go b/examples/baremetal/tar.go index 17ee8599..61dfd0fb 100644 --- a/examples/baremetal/tar.go +++ b/examples/baremetal/tar.go @@ -28,13 +28,12 @@ func AllFiles(dir string, exclude ...string) ([]string, error) { if !d.Type().IsRegular() { return nil } - fn := d.Name() for _, ex := range exclude { - if errors.Log1(filepath.Match(ex, fn)) { + if errors.Log1(filepath.Match(ex, path)) { return nil } } - files = append(files, fn) + files = append(files, path) return nil }) return files, err diff --git a/examples/pca/README.md b/examples/pca/README.md new file mode 100644 index 00000000..51bbe4d5 --- /dev/null +++ b/examples/pca/README.md @@ -0,0 +1,6 @@ +# PCA example + +This example performs PCA on the iris dataset from the UCI machine learning repository. + +It should probably be moved into docs at some point instead, and cleaned up. But it is not clear how to handle the data itself in that context. + diff --git a/examples/pca/iris.data b/examples/pca/iris.data new file mode 100644 index 00000000..1a9f95dc --- /dev/null +++ b/examples/pca/iris.data @@ -0,0 +1,152 @@ +%SepalLength,%SepalWidth,%PetalLength,%PetalWidth,$Name +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3.0,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5.0,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5.0,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3.0,1.4,0.1,Iris-setosa +4.3,3.0,1.1,0.1,Iris-setosa +5.8,4.0,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1.0,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +5.0,3.0,1.6,0.2,Iris-setosa +5.0,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.0,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3.0,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5.0,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5.0,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3.0,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5.0,3.3,1.4,0.2,Iris-setosa +7.0,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4.0,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1.0,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5.0,2.0,3.5,1.0,Iris-versicolor +5.9,3.0,4.2,1.5,Iris-versicolor +6.0,2.2,4.0,1.0,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3.0,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1.0,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4.0,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.6,3.0,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3.0,5.0,1.7,Iris-versicolor +6.0,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1.0,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1.0,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6.0,2.7,5.1,1.6,Iris-versicolor +5.4,3.0,4.5,1.5,Iris-versicolor +6.0,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3.0,4.1,1.3,Iris-versicolor +5.5,2.5,4.0,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3.0,4.6,1.4,Iris-versicolor +5.8,2.6,4.0,1.2,Iris-versicolor +5.0,2.3,3.3,1.0,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3.0,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3.0,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor +6.3,3.3,6.0,2.5,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +7.1,3.0,5.9,2.1,Iris-virginica +6.3,2.9,5.6,1.8,Iris-virginica +6.5,3.0,5.8,2.2,Iris-virginica +7.6,3.0,6.6,2.1,Iris-virginica +4.9,2.5,4.5,1.7,Iris-virginica +7.3,2.9,6.3,1.8,Iris-virginica +6.7,2.5,5.8,1.8,Iris-virginica +7.2,3.6,6.1,2.5,Iris-virginica +6.5,3.2,5.1,2.0,Iris-virginica +6.4,2.7,5.3,1.9,Iris-virginica +6.8,3.0,5.5,2.1,Iris-virginica +5.7,2.5,5.0,2.0,Iris-virginica +5.8,2.8,5.1,2.4,Iris-virginica +6.4,3.2,5.3,2.3,Iris-virginica +6.5,3.0,5.5,1.8,Iris-virginica +7.7,3.8,6.7,2.2,Iris-virginica +7.7,2.6,6.9,2.3,Iris-virginica +6.0,2.2,5.0,1.5,Iris-virginica +6.9,3.2,5.7,2.3,Iris-virginica +5.6,2.8,4.9,2.0,Iris-virginica +7.7,2.8,6.7,2.0,Iris-virginica +6.3,2.7,4.9,1.8,Iris-virginica +6.7,3.3,5.7,2.1,Iris-virginica +7.2,3.2,6.0,1.8,Iris-virginica +6.2,2.8,4.8,1.8,Iris-virginica +6.1,3.0,4.9,1.8,Iris-virginica +6.4,2.8,5.6,2.1,Iris-virginica +7.2,3.0,5.8,1.6,Iris-virginica +7.4,2.8,6.1,1.9,Iris-virginica +7.9,3.8,6.4,2.0,Iris-virginica +6.4,2.8,5.6,2.2,Iris-virginica +6.3,2.8,5.1,1.5,Iris-virginica +6.1,2.6,5.6,1.4,Iris-virginica +7.7,3.0,6.1,2.3,Iris-virginica +6.3,3.4,5.6,2.4,Iris-virginica +6.4,3.1,5.5,1.8,Iris-virginica +6.0,3.0,4.8,1.8,Iris-virginica +6.9,3.1,5.4,2.1,Iris-virginica +6.7,3.1,5.6,2.4,Iris-virginica +6.9,3.1,5.1,2.3,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +6.8,3.2,5.9,2.3,Iris-virginica +6.7,3.3,5.7,2.5,Iris-virginica +6.7,3.0,5.2,2.3,Iris-virginica +6.3,2.5,5.0,1.9,Iris-virginica +6.5,3.0,5.2,2.0,Iris-virginica +6.2,3.4,5.4,2.3,Iris-virginica +5.9,3.0,5.1,1.8,Iris-virginica + diff --git a/examples/pca/iris_nohead.data b/examples/pca/iris_nohead.data new file mode 100644 index 00000000..5c4316cd --- /dev/null +++ b/examples/pca/iris_nohead.data @@ -0,0 +1,151 @@ +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3.0,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5.0,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5.0,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3.0,1.4,0.1,Iris-setosa +4.3,3.0,1.1,0.1,Iris-setosa +5.8,4.0,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1.0,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +5.0,3.0,1.6,0.2,Iris-setosa +5.0,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.0,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3.0,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5.0,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5.0,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3.0,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5.0,3.3,1.4,0.2,Iris-setosa +7.0,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4.0,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1.0,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5.0,2.0,3.5,1.0,Iris-versicolor +5.9,3.0,4.2,1.5,Iris-versicolor +6.0,2.2,4.0,1.0,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3.0,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1.0,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4.0,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.6,3.0,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3.0,5.0,1.7,Iris-versicolor +6.0,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1.0,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1.0,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6.0,2.7,5.1,1.6,Iris-versicolor +5.4,3.0,4.5,1.5,Iris-versicolor +6.0,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3.0,4.1,1.3,Iris-versicolor +5.5,2.5,4.0,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3.0,4.6,1.4,Iris-versicolor +5.8,2.6,4.0,1.2,Iris-versicolor +5.0,2.3,3.3,1.0,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3.0,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3.0,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor +6.3,3.3,6.0,2.5,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +7.1,3.0,5.9,2.1,Iris-virginica +6.3,2.9,5.6,1.8,Iris-virginica +6.5,3.0,5.8,2.2,Iris-virginica +7.6,3.0,6.6,2.1,Iris-virginica +4.9,2.5,4.5,1.7,Iris-virginica +7.3,2.9,6.3,1.8,Iris-virginica +6.7,2.5,5.8,1.8,Iris-virginica +7.2,3.6,6.1,2.5,Iris-virginica +6.5,3.2,5.1,2.0,Iris-virginica +6.4,2.7,5.3,1.9,Iris-virginica +6.8,3.0,5.5,2.1,Iris-virginica +5.7,2.5,5.0,2.0,Iris-virginica +5.8,2.8,5.1,2.4,Iris-virginica +6.4,3.2,5.3,2.3,Iris-virginica +6.5,3.0,5.5,1.8,Iris-virginica +7.7,3.8,6.7,2.2,Iris-virginica +7.7,2.6,6.9,2.3,Iris-virginica +6.0,2.2,5.0,1.5,Iris-virginica +6.9,3.2,5.7,2.3,Iris-virginica +5.6,2.8,4.9,2.0,Iris-virginica +7.7,2.8,6.7,2.0,Iris-virginica +6.3,2.7,4.9,1.8,Iris-virginica +6.7,3.3,5.7,2.1,Iris-virginica +7.2,3.2,6.0,1.8,Iris-virginica +6.2,2.8,4.8,1.8,Iris-virginica +6.1,3.0,4.9,1.8,Iris-virginica +6.4,2.8,5.6,2.1,Iris-virginica +7.2,3.0,5.8,1.6,Iris-virginica +7.4,2.8,6.1,1.9,Iris-virginica +7.9,3.8,6.4,2.0,Iris-virginica +6.4,2.8,5.6,2.2,Iris-virginica +6.3,2.8,5.1,1.5,Iris-virginica +6.1,2.6,5.6,1.4,Iris-virginica +7.7,3.0,6.1,2.3,Iris-virginica +6.3,3.4,5.6,2.4,Iris-virginica +6.4,3.1,5.5,1.8,Iris-virginica +6.0,3.0,4.8,1.8,Iris-virginica +6.9,3.1,5.4,2.1,Iris-virginica +6.7,3.1,5.6,2.4,Iris-virginica +6.9,3.1,5.1,2.3,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +6.8,3.2,5.9,2.3,Iris-virginica +6.7,3.3,5.7,2.5,Iris-virginica +6.7,3.0,5.2,2.3,Iris-virginica +6.3,2.5,5.0,1.9,Iris-virginica +6.5,3.0,5.2,2.0,Iris-virginica +6.2,3.4,5.4,2.3,Iris-virginica +5.9,3.0,5.1,1.8,Iris-virginica + diff --git a/examples/pca/pca.go b/examples/pca/pca.go new file mode 100644 index 00000000..6213abd6 --- /dev/null +++ b/examples/pca/pca.go @@ -0,0 +1,112 @@ +// Copyright (c) 2024, Cogent Core. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + + "cogentcore.org/core/cli" + "cogentcore.org/core/core" + "cogentcore.org/core/events" + "cogentcore.org/core/icons" + "cogentcore.org/core/tree" + "cogentcore.org/lab/goal/interpreter" + "cogentcore.org/lab/lab" + "cogentcore.org/lab/matrix" + "cogentcore.org/lab/stats/metric" + "cogentcore.org/lab/table" + "cogentcore.org/lab/tensor" + "cogentcore.org/lab/tensorfs" + "cogentcore.org/lab/yaegilab/labsymbols" +) + +// important: must be run from an interactive terminal. +// Will quit immediately if not! +func main() { + opts := cli.DefaultOptions("iris", "interactive data analysis.") + cfg := &interpreter.Config{} + cfg.InteractiveFunc = Interactive + cli.Run(opts, cfg, interpreter.Run, interpreter.Build) +} + +func Interactive(c *interpreter.Config, in *interpreter.Interpreter) error { + dir := tensorfs.Mkdir("Iris") + b, bs := lab.NewBasicWindow(tensorfs.CurRoot, "Iris", in) + in.Interp.Use(labsymbols.Symbols) + in.Config() + b.AddTopBar(func(bar *core.Frame) { + tb := core.NewToolbar(bar) + // tb.Maker(tbv.MakeToolbar) + tb.Maker(func(p *tree.Plan) { + tree.Add(p, func(w *core.Button) { + w.SetText("README").SetIcon(icons.FileMarkdown). + SetTooltip("open README help file").OnClick(func(e events.Event) { + core.TheApp.OpenURL("https://github.com/cogentcore/lab/blob/main/examples/pca/README.md") + }) + }) + }) + }) + b.OnShow(func(e events.Event) { + go func() { + if c.Expr != "" { + in.Eval(c.Expr) + } + AnalyzeIris(dir, bs) + in.Interactive() + }() + }) + + b.RunWindow() + core.Wait() + return nil +} + +func AnalyzeIris(dir *tensorfs.Node, bs *lab.Basic) { + dt := table.New("iris") + err := dt.OpenCSV("iris.data", tensor.Comma) + if err != nil { + fmt.Println(err) + return + } + + ddir := dir.Dir("Data") + tensorfs.DirFromTable(ddir, dt) + + ped := bs.Tabs.PlotTable("Iris", dt) + _ = ped + + cdt := table.New() + cdt.AddFloat64Column("data", 4) + cdt.AddStringColumn("class") + err = cdt.OpenCSV("iris_nohead.data", tensor.Comma) + if err != nil { + fmt.Println(err) + return + } + data := cdt.Column("data") + covar := tensor.NewFloat64() + err = metric.CovarianceMatrixOut(metric.Correlation, data, covar) + cvg := bs.Tabs.TensorGrid("Covar", covar) + _ = cvg + + vecs, _ := matrix.EigSym(covar) + + pcdir := dir.Dir("PCA") + tensorfs.SetTensor(pcdir, tensor.Reslice(vecs, 3, tensor.FullAxis), "pc0") + tensorfs.SetTensor(pcdir, tensor.Reslice(vecs, 2, tensor.FullAxis), "pc1") + + colidx := tensor.NewFloat64Scalar(3) // strongest at end + prjn0 := tensor.NewFloat64() + matrix.ProjectOnMatrixColumnOut(vecs, data, colidx, prjn0) + + pjdir := dir.Dir("Prjn") + tensorfs.SetTensor(pjdir, prjn0, "pc0") + colidx = tensor.NewFloat64Scalar(2) + prjn1 := tensor.NewFloat64() + matrix.ProjectOnMatrixColumnOut(vecs, data, colidx, prjn1) + tensorfs.SetTensor(pjdir, prjn1, "pc1") + + tensorfs.SetTensor(pjdir, dt.Column("Name"), "name") +} diff --git a/examples/simmer/README.md b/examples/simmer/README.md index 7473b6e2..bfe7de8e 100644 --- a/examples/simmer/README.md +++ b/examples/simmer/README.md @@ -4,6 +4,12 @@ Simmer provides a Cogent Lab based GUI for running simulation jobs, and managing and analyzing the resulting data, using the plotcore Editor. It supports both slurm and [baremetal](../baremetal) job management systems. +The local data goes into paths like this: + +`~/simdata/simname/user` with `jobs` and `labscripts` subdirectories + +The server data goes into similar paths but starting with `~/simserver` instead. + # Server types ## Slurm @@ -14,4 +20,12 @@ The slurm backend uses array jobs to distribute computation over many CPU nodes. If not using slurm, then the [baremetal](../baremetal) system manages jobs itself, maintaining a record of the jobs launched relative to the resources available. +baremetal can be run on localhost to manage jobs on your own local machine, using this config: + +```toml +[[Servers.Values]] + Name = "lh" + SSH = "localhost" + NGPUs = 4 +``` diff --git a/examples/simmer/bare.go b/examples/simmer/bare.go index 1fc049a9..023152af 100644 --- a/examples/simmer/bare.go +++ b/examples/simmer/bare.go @@ -31,7 +31,7 @@ func (sr *Simmer) SubmitBare(jid, args string) string { f.Close() goalrun.Run("chmod", "+x", script) - files, err := baremetal.AllFiles("./", ".*") + files, err := baremetal.AllFiles("./", ".*") // no .DS_Store etc if errors.Log(err) != nil { return "" } @@ -73,8 +73,14 @@ func (sr *Simmer) WriteBare(w io.Writer, jid, args string) { fmt.Fprintln(w, sr.Config.SetupScript) } - // fmt.Fprintf(w, "go build -mod=mod -tags mpi\n") - fmt.Fprintf(w, "go build -mod=mod\n") + if sr.Config.Job.SubCmd { + fmt.Fprintf(w, "cd cmd\n") + fmt.Fprintf(w, "go build -mod=mod %s\n", sr.Config.Job.BuildArgs) + fmt.Fprintf(w, "mv cmd ../%s\n", sr.Config.Project) + fmt.Fprintf(w, "cd ../\n") + } else { + fmt.Fprintf(w, "go build -mod=mod %s\n", sr.Config.Job.BuildArgs) + } cmd := `date '+%Y-%m-%d %T %Z' > job.start` fmt.Fprintln(w, cmd) diff --git a/examples/simmer/bare.goal b/examples/simmer/bare.goal index bae92ab0..1c95b73e 100644 --- a/examples/simmer/bare.goal +++ b/examples/simmer/bare.goal @@ -29,12 +29,12 @@ func (sr *Simmer) SubmitBare(jid, args string) string { f.Close() chmod +x {script} - files, err := baremetal.AllFiles("./", ".*") + files, err := baremetal.AllFiles("./", ".*") // no .DS_Store etc if errors.Log(err) != nil { return "" } // fmt.Println("files:", files) - // todo: this is triggering a type defn mode: + // todo: this is triggering a type defn mode: {var b bytes.Buffer} err = baremetal.TarFiles(&b, "./", true, files...) if errors.Log(err) != nil { @@ -71,8 +71,14 @@ func (sr *Simmer) WriteBare(w io.Writer, jid, args string) { fmt.Fprintln(w, sr.Config.SetupScript) } - // fmt.Fprintf(w, "go build -mod=mod -tags mpi\n") - fmt.Fprintf(w, "go build -mod=mod\n") + if sr.Config.Job.SubCmd { + fmt.Fprintf(w, "cd cmd\n") + fmt.Fprintf(w, "go build -mod=mod %s\n", sr.Config.Job.BuildArgs) + fmt.Fprintf(w, "mv cmd ../%s\n", sr.Config.Project) + fmt.Fprintf(w, "cd ../\n") + } else { + fmt.Fprintf(w, "go build -mod=mod %s\n", sr.Config.Job.BuildArgs) + } cmd := `date '+%Y-%m-%d %T %Z' > job.start` fmt.Fprintln(w, cmd) diff --git a/examples/simmer/config.go b/examples/simmer/config.go index f02c77f2..60d20fc3 100644 --- a/examples/simmer/config.go +++ b/examples/simmer/config.go @@ -16,7 +16,7 @@ import ( // FilterResults specifies which results files to open. type FilterResults struct { - // File name contains this string, e.g., "_epc" or "_run" + // File name contains this string, e.g., "_epoch" or "_run" FileContains string `width:"60"` // extension of files, e.g., .tsv @@ -70,6 +70,14 @@ type JobParams struct { // Qos is the queue "quality of service" name. Qos string + + // If true, the executable is in a cmd subdirectory, filename main.go, + // to allow the primary directory to be imported into other apps. + // Manages the copying and building of this sub-command. + SubCmd bool + + // BuildArgs are extra arts to pass during building, such as -tags mpi for mpi + BuildArgs string } func (jp *JobParams) Defaults() { @@ -89,7 +97,7 @@ type ServerParams struct { Name string // Root is the root path from user home dir on server. - // is auto-set to: filepath.Join("simdata", Project, User) + // is auto-set to: filepath.Join("simserver", Project, User) Root string // Slurm uses the slurm job manager. Otherwise uses a bare job manager. @@ -198,7 +206,7 @@ func (cf *Configuration) Defaults() { func (cf *Configuration) Update() { cf.UserShort = cf.User[:3] - cf.Server.Root = filepath.Join("simdata", cf.Project, cf.User) + cf.Server.Root = filepath.Join("simserver", cf.Project, cf.User) } // Result has info for one loaded result, as a table.Table diff --git a/examples/simmer/config.goal b/examples/simmer/config.goal index 21009e09..e9649f4f 100644 --- a/examples/simmer/config.goal +++ b/examples/simmer/config.goal @@ -14,7 +14,7 @@ import ( // FilterResults specifies which results files to open. type FilterResults struct { - // File name contains this string, e.g., "_epc" or "_run" + // File name contains this string, e.g., "_epoch" or "_run" FileContains string `width:"60"` // extension of files, e.g., .tsv @@ -67,6 +67,14 @@ type JobParams struct { // Qos is the queue "quality of service" name. Qos string + + // If true, the executable is in a cmd subdirectory, filename main.go, + // to allow the primary directory to be imported into other apps. + // Manages the copying and building of this sub-command. + SubCmd bool + + // BuildArgs are extra arts to pass during building, such as -tags mpi for mpi + BuildArgs string } func (jp *JobParams) Defaults() { @@ -86,7 +94,7 @@ type ServerParams struct { Name string // Root is the root path from user home dir on server. - // is auto-set to: filepath.Join("simdata", Project, User) + // is auto-set to: filepath.Join("simserver", Project, User) Root string // Slurm uses the slurm job manager. Otherwise uses a bare job manager. @@ -195,7 +203,7 @@ func (cf *Configuration) Defaults() { func (cf *Configuration) Update() { cf.UserShort = cf.User[:3] - cf.Server.Root = filepath.Join("simdata", cf.Project, cf.User) + cf.Server.Root = filepath.Join("simserver", cf.Project, cf.User) } // Result has info for one loaded result, as a table.Table diff --git a/examples/simmer/submit.go b/examples/simmer/submit.go index bf109800..2be00058 100644 --- a/examples/simmer/submit.go +++ b/examples/simmer/submit.go @@ -9,6 +9,7 @@ package main import ( "fmt" "os" + "path" "path/filepath" "strconv" "strings" @@ -53,54 +54,32 @@ func (sr *Simmer) FindGoMod(dir string) string { return "" } -// GoModulePath returns the overall module path for project -// in given directory, and the full module path to the current -// project, which is a subdirectory within the module. -func (sr *Simmer) GoModulePath(dir string) (modpath, fullpath string) { - goalrun.Run("@0") - os.Chdir(dir) - goalrun.Run("cd", dir) - gg := goalib.SplitLines(goalrun.Output("go", "mod", "graph")) - gg = strings.Fields(gg[0]) - if len(gg) == 0 { - fmt.Println("GoModulePath: unexpected error: system seems to be out of whack") - return - } - modpath = gg[0] - - // strategy: go up the dir until the dir name matches the last element of modpath - dirsp := strings.Split(dir, "/") - n := len(dirsp) - for i := n - 1; i >= 0; i-- { - d := dirsp[i] - if strings.HasSuffix(modpath, d) { - fullpath = filepath.Join(modpath, strings.Join(dirsp[i+1:], "/")) - break - } - } - return -} - // CopyFilesToJob copies files with given extensions (none for all), // from localSrc to localJob and remote hostJob (@1). -// Ensures directories are made in the job locations -func (sr *Simmer) CopyFilesToJob(localSrc, localJob, hostJob string, exts ...string) { +// Ensures directories are made in the job locations. +// If origProjPath and projPath are non-empty, and file is .go file, then the +// origProjPath -> projPath replacement. +func (sr *Simmer) CopyFilesToJob(localSrc, localJob, hostJob, origProjPath, projPath string, exts ...string) { goalrun.Run("@0") - if !sr.IsSlurm() { // baremetal does it separately - return - } goalrun.Run("mkdir", "-p", localJob) goalrun.Run("cd", localJob) - goalrun.Run("@1") - goalrun.Run("cd") - goalrun.Run("mkdir", "-p", hostJob) - goalrun.Run("cd", hostJob) - goalrun.Run("@0") + if sr.IsSlurm() { + goalrun.Run("@1") + goalrun.Run("cd") + goalrun.Run("mkdir", "-p", hostJob) + goalrun.Run("cd", hostJob) + goalrun.Run("@0") + } efls := fsx.Filenames(localSrc, exts...) for _, f := range efls { sfn := filepath.Join(localSrc, f) goalrun.Run("/bin/cp", sfn, f) - goalrun.Run("scp", sfn, "@1:"+f) + if projPath != "" && strings.HasSuffix(f, ".go") { + goalib.ReplaceInFile(f, origProjPath, projPath) + } + if sr.IsSlurm() { + goalrun.Run("scp", f, "@1:"+f) + } } } @@ -121,10 +100,10 @@ func (sr *Simmer) NewJob(jp SubmitParams) { isSlurm := sr.IsSlurm() gomodDir := sr.FindGoMod(sr.StartDir) - _, fullPath := sr.GoModulePath(sr.StartDir) - projPath := filepath.Join("emer", sr.Config.Project) - - // fmt.Println("go.mod:", gomodDir, "\nmodule:", modulePath, "\nfull path:", fullPath, "\njob proj:", projPath) + subDir := strings.TrimPrefix(sr.StartDir, gomodDir) + projPath := path.Join("emer", subDir) + origProjPath := path.Join(sr.Config.Package, subDir) + // fmt.Println("gmd:", gomodDir, "sd:", subDir, "pp:", projPath, "opp:", origProjPath) // fmt.Println(jpath) os.MkdirAll(jpath, 0750) @@ -136,14 +115,16 @@ func (sr *Simmer) NewJob(jp SubmitParams) { goalib.WriteFile("job.status", "Submitted") // need to do sub-code first and update paths in copied files - codepaths := make([]string, len(sr.Config.CodeDirs)) - for i, ed := range sr.Config.CodeDirs { + cdirs := sr.Config.CodeDirs + if sr.Config.Job.SubCmd { + cdirs = append(cdirs, "cmd") + } + for _, ed := range cdirs { goalrun.Run("@0") loce := filepath.Join(sr.StartDir, ed) - codepaths[i] = filepath.Join(fullPath, ed) jpathe := filepath.Join(jpath, ed) spathe := filepath.Join(spath, ed) - sr.CopyFilesToJob(loce, jpathe, spathe, ".go") + sr.CopyFilesToJob(loce, jpathe, spathe, origProjPath, projPath, ".go") } // copy local files: if isSlurm { @@ -158,11 +139,7 @@ func (sr *Simmer) NewJob(jp SubmitParams) { for _, f := range fls { sfn := filepath.Join(sr.StartDir, f) goalrun.Run("/bin/cp", sfn, f) - for i, ed := range sr.Config.CodeDirs { - subpath := filepath.Join(projPath, ed) - // fmt.Println("replace in:", f, codepaths[i], "->", subpath) - goalib.ReplaceInFile(f, codepaths[i], subpath) - } + goalib.ReplaceInFile(f, origProjPath, projPath) if isSlurm { goalrun.Run("scp", f, "@1:"+f) } @@ -178,7 +155,7 @@ func (sr *Simmer) NewJob(jp SubmitParams) { jpathe := filepath.Join(jpath, ed) spathe := filepath.Join(spath, ed) loce := filepath.Join(sr.StartDir, ed) - sr.CopyFilesToJob(loce, jpathe, spathe) + sr.CopyFilesToJob(loce, jpathe, spathe, "", "") } if isSlurm { goalrun.Run("@1") diff --git a/examples/simmer/submit.goal b/examples/simmer/submit.goal index 75250e95..7338a27c 100644 --- a/examples/simmer/submit.goal +++ b/examples/simmer/submit.goal @@ -7,6 +7,7 @@ package main import ( "fmt" "os" + "path" "path/filepath" "strings" "strconv" @@ -51,54 +52,32 @@ func (sr *Simmer) FindGoMod(dir string) string { return "" } -// GoModulePath returns the overall module path for project -// in given directory, and the full module path to the current -// project, which is a subdirectory within the module. -func (sr *Simmer) GoModulePath(dir string) (modpath, fullpath string) { - @0 - os.Chdir(dir) - cd {dir} - gg := goalib.SplitLines($go mod graph$) - gg = strings.Fields(gg[0]) - if len(gg) == 0 { - fmt.Println("GoModulePath: unexpected error: system seems to be out of whack") - return - } - modpath = gg[0] - - // strategy: go up the dir until the dir name matches the last element of modpath - dirsp := strings.Split(dir, "/") - n := len(dirsp) - for i := n-1; i >= 0; i-- { - d := dirsp[i] - if strings.HasSuffix(modpath, d) { - fullpath = filepath.Join(modpath, strings.Join(dirsp[i+1:], "/")) - break - } - } - return -} - // CopyFilesToJob copies files with given extensions (none for all), // from localSrc to localJob and remote hostJob (@1). -// Ensures directories are made in the job locations -func (sr *Simmer) CopyFilesToJob(localSrc, localJob, hostJob string, exts ...string) { +// Ensures directories are made in the job locations. +// If origProjPath and projPath are non-empty, and file is .go file, then the +// origProjPath -> projPath replacement. +func (sr *Simmer) CopyFilesToJob(localSrc, localJob, hostJob, origProjPath, projPath string, exts ...string) { @0 - if !sr.IsSlurm() { // baremetal does it separately - return - } mkdir -p {localJob} cd {localJob} - @1 - cd - mkdir -p {hostJob} - cd {hostJob} - @0 + if sr.IsSlurm() { + @1 + cd + mkdir -p {hostJob} + cd {hostJob} + @0 + } efls := fsx.Filenames(localSrc, exts...) for _, f := range efls { sfn := filepath.Join(localSrc, f) /bin/cp {sfn} {f} - scp {sfn} {"@1:"+f} + if projPath != "" && strings.HasSuffix(f, ".go") { + goalib.ReplaceInFile(f, origProjPath, projPath) + } + if sr.IsSlurm() { + scp {f} {"@1:"+f} + } } } @@ -119,10 +98,10 @@ func (sr *Simmer) NewJob(jp SubmitParams) { isSlurm := sr.IsSlurm() gomodDir := sr.FindGoMod(sr.StartDir) - _, fullPath := sr.GoModulePath(sr.StartDir) - projPath := filepath.Join("emer", sr.Config.Project) - - // fmt.Println("go.mod:", gomodDir, "\nmodule:", modulePath, "\nfull path:", fullPath, "\njob proj:", projPath) + subDir := strings.TrimPrefix(sr.StartDir, gomodDir) + projPath := path.Join("emer", subDir) + origProjPath := path.Join(sr.Config.Package, subDir) + // fmt.Println("gmd:", gomodDir, "sd:", subDir, "pp:", projPath, "opp:", origProjPath) // fmt.Println(jpath) os.MkdirAll(jpath, 0750) @@ -134,14 +113,16 @@ func (sr *Simmer) NewJob(jp SubmitParams) { goalib.WriteFile("job.status", "Submitted") // need to do sub-code first and update paths in copied files - codepaths := make([]string, len(sr.Config.CodeDirs)) - for i, ed := range sr.Config.CodeDirs { + cdirs := sr.Config.CodeDirs + if sr.Config.Job.SubCmd { + cdirs = append(cdirs, "cmd") + } + for _, ed := range cdirs { @0 loce := filepath.Join(sr.StartDir, ed) - codepaths[i] = filepath.Join(fullPath, ed) jpathe := filepath.Join(jpath, ed) spathe := filepath.Join(spath, ed) - sr.CopyFilesToJob(loce, jpathe, spathe, ".go") + sr.CopyFilesToJob(loce, jpathe, spathe, origProjPath, projPath, ".go") } // copy local files: if isSlurm { @@ -156,11 +137,7 @@ func (sr *Simmer) NewJob(jp SubmitParams) { for _, f := range fls { sfn := filepath.Join(sr.StartDir, f) /bin/cp {sfn} {f} - for i, ed := range sr.Config.CodeDirs { - subpath := filepath.Join(projPath, ed) - // fmt.Println("replace in:", f, codepaths[i], "->", subpath) - goalib.ReplaceInFile(f, codepaths[i], subpath) - } + goalib.ReplaceInFile(f, origProjPath, projPath) if isSlurm { scp {f} {"@1:"+f} } @@ -176,7 +153,7 @@ func (sr *Simmer) NewJob(jp SubmitParams) { jpathe := filepath.Join(jpath, ed) spathe := filepath.Join(spath, ed) loce := filepath.Join(sr.StartDir, ed) - sr.CopyFilesToJob(loce, jpathe, spathe) + sr.CopyFilesToJob(loce, jpathe, spathe, "", "") } if isSlurm { @1 diff --git a/examples/simmer/typegen.go b/examples/simmer/typegen.go index 91ffa4e3..2c2f379d 100644 --- a/examples/simmer/typegen.go +++ b/examples/simmer/typegen.go @@ -15,9 +15,9 @@ var _ = types.AddType(&types.Type{Name: "main.FilterResults", IDName: "filter-re var _ = types.AddType(&types.Type{Name: "main.SubmitParams", IDName: "submit-params", Doc: "SubmitParams specifies the parameters for submitting a job.", Fields: []types.Field{{Name: "Message", Doc: "Message describing the simulation:\nthis is key info for what is special about this job, like a github commit message"}, {Name: "Label", Doc: "Label is brief, unique label used for plots to label this job"}, {Name: "Args", Doc: "\targuments to pass on the command line.\n\n-nogui is already passed by default"}}}) -var _ = types.AddType(&types.Type{Name: "main.JobParams", IDName: "job-params", Doc: "JobParams are parameters for running the job", Fields: []types.Field{{Name: "NRuns", Doc: "NRuns is the number of parallel runs; can also set to 1\nand run multiple runs per job using args."}, {Name: "Hours", Doc: "Hours is the max number of hours: slurm will terminate if longer,\nso be generous 2d = 48, 3d = 72, 4d = 96, 5d = 120, 6d = 144, 7d = 168"}, {Name: "Memory", Doc: "Memory per CPU in gigabytes"}, {Name: "Tasks", Doc: "Tasks is the number of mpi \"tasks\" (procs in MPI terminology)."}, {Name: "CPUsPerTask", Doc: "CPUsPerTask is the number of cpu cores (threads) per task."}, {Name: "TasksPerNode", Doc: "TasksPerNode is how to allocate tasks within compute nodes\ncpus_per_task * tasks_per_node <= total cores per node."}, {Name: "Qos", Doc: "Qos is the queue \"quality of service\" name."}}}) +var _ = types.AddType(&types.Type{Name: "main.JobParams", IDName: "job-params", Doc: "JobParams are parameters for running the job", Fields: []types.Field{{Name: "NRuns", Doc: "NRuns is the number of parallel runs; can also set to 1\nand run multiple runs per job using args."}, {Name: "Hours", Doc: "Hours is the max number of hours: slurm will terminate if longer,\nso be generous 2d = 48, 3d = 72, 4d = 96, 5d = 120, 6d = 144, 7d = 168"}, {Name: "Memory", Doc: "Memory per CPU in gigabytes"}, {Name: "Tasks", Doc: "Tasks is the number of mpi \"tasks\" (procs in MPI terminology)."}, {Name: "CPUsPerTask", Doc: "CPUsPerTask is the number of cpu cores (threads) per task."}, {Name: "TasksPerNode", Doc: "TasksPerNode is how to allocate tasks within compute nodes\ncpus_per_task * tasks_per_node <= total cores per node."}, {Name: "Qos", Doc: "Qos is the queue \"quality of service\" name."}, {Name: "SubCmd", Doc: "If true, the executable is in a cmd subdirectory, filename main.go,\nto allow the primary directory to be imported into other apps.\nManages the copying and building of this sub-command."}, {Name: "BuildArgs", Doc: "BuildArgs are extra arts to pass during building, such as -tags mpi for mpi"}}}) -var _ = types.AddType(&types.Type{Name: "main.ServerParams", IDName: "server-params", Doc: "ServerParams are parameters for the server.", Fields: []types.Field{{Name: "Name", Doc: "Name is the name of current server using to run jobs;\ngets recorded with each job."}, {Name: "Root", Doc: "Root is the root path from user home dir on server.\nis auto-set to: filepath.Join(\"simdata\", Project, User)"}, {Name: "Slurm", Doc: "Slurm uses the slurm job manager. Otherwise uses a bare job manager."}}}) +var _ = types.AddType(&types.Type{Name: "main.ServerParams", IDName: "server-params", Doc: "ServerParams are parameters for the server.", Fields: []types.Field{{Name: "Name", Doc: "Name is the name of current server using to run jobs;\ngets recorded with each job."}, {Name: "Root", Doc: "Root is the root path from user home dir on server.\nis auto-set to: filepath.Join(\"simserver\", Project, User)"}, {Name: "Slurm", Doc: "Slurm uses the slurm job manager. Otherwise uses a bare job manager."}}}) var _ = types.AddType(&types.Type{Name: "main.Configuration", IDName: "configuration", Doc: "Configuration holds all of the user-settable parameters", Fields: []types.Field{{Name: "DataRoot", Doc: "DataRoot is the path to the root of the data to browse."}, {Name: "StartDir", Doc: "StartDir is the starting directory, where the app was originally started."}, {Name: "User", Doc: "User id as in system login name (i.e., user@system)."}, {Name: "UserShort", Doc: "UserShort is the first 3 letters of User,\nfor naming jobs (auto-set from User)."}, {Name: "Project", Doc: "Project is the name of simulation project, lowercase\n(should be name of source dir)."}, {Name: "Package", Doc: "Package is the parent package: e.g., github.com/emer/axon/v2\nThis is used to update the go.mod, along with the Version."}, {Name: "Version", Doc: "Version is the current git version string, from git describe --tags."}, {Name: "Job", Doc: "Job has the parameters for job resources etc."}, {Name: "Server", Doc: "Server has server parameters."}, {Name: "FetchFiles", Doc: "FetchFiles is a glob expression for files to fetch from server,\nfor Fetch command. Is *.tsv by default."}, {Name: "ExcludeNodes", Doc: "ExcludeNodes are nodes to exclude from job, based on what is slow."}, {Name: "ExtraFiles", Doc: "ExtraFiles has extra files to upload with job submit, from same dir."}, {Name: "ExtraDirs", Doc: "ExtraDirs has subdirs with other files to upload with job submit\n(non-code -- see CodeDirs)."}, {Name: "CodeDirs", Doc: "CodeDirs has subdirs with code to upload with job submit;\ngo.mod auto-updated to use."}, {Name: "ExtraGoGet", Doc: "ExtraGoGet is an extra package to do \"go get\" with, for launching the job."}, {Name: "JobScript", Doc: "JobScript is a job script to use for running the simulation,\ninstead of the basic default, if non-empty.\nThis is written to the job.sbatch file. If it contains a $JOB_ARGS string\nthen that is replaced with the args entered during submission.\nIf using slurm, this switches to a simple direct sbatch submission instead\nof the default parallel job submission. All standard slurm job parameters\nare automatically inserted at the start of the file, so this script should\njust be the actual job running actions after that point."}, {Name: "SetupScript", Doc: "SetupScript contains optional lines of bash script code to insert at\nthe start of the job submission script, which is then followed by\nthe default script. For example, if a symbolic link to a large shared\nresource is needed, make that link here."}, {Name: "TimeFormat", Doc: "TimeFormat is the format for timestamps,\ndefaults to \"2006-01-02 15:04:05 MST\""}, {Name: "Filter", Doc: "Filter has parameters for filtering results."}, {Name: "Submit", Doc: "Submit has parameters for submitting jobs; set from last job run."}}}) diff --git a/go.mod b/go.mod index 5673e65b..2b2471c1 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ go 1.23.4 // https://github.com/googleapis/go-genproto/issues/1015 require ( - cogentcore.org/core v0.3.12-0.20250523214429-baa6838472a6 + cogentcore.org/core v0.3.12-0.20250622201146-a16b152763fe github.com/cogentcore/readline v0.1.3 github.com/cogentcore/yaegi v0.0.0-20240724064145-e32a03faad56 github.com/mitchellh/go-homedir v1.1.0 @@ -17,7 +17,7 @@ require ( golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/tools v0.23.0 gonum.org/v1/gonum v0.15.0 - google.golang.org/grpc v1.72.0 + google.golang.org/grpc v1.72.1 google.golang.org/protobuf v1.36.6 ) @@ -58,14 +58,14 @@ require ( github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/tdewolff/parse/v2 v2.7.19 // indirect github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 // indirect - golang.org/x/crypto v0.37.0 // indirect + golang.org/x/crypto v0.38.0 // indirect golang.org/x/image v0.25.0 // indirect golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.24.0 // indirect - google.golang.org/genproto v0.0.0-20250519155744-55703ea1f237 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 324ae32a..3d720925 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cogentcore.org/core v0.3.12-0.20250523214429-baa6838472a6 h1:Ojlif/nOVeznuGSrA4UVasnVR53kpo3c3GcTafuEmzo= -cogentcore.org/core v0.3.12-0.20250523214429-baa6838472a6/go.mod h1:A82XMVcq3XOiG9TpT+rt7/iYD5Eu87bxxmTk8O7F4cM= +cogentcore.org/core v0.3.12-0.20250622201146-a16b152763fe h1:Q8xl3SzvUB/TLaGlXoXQSm+gljmjA7c+d5p8ubXO4DI= +cogentcore.org/core v0.3.12-0.20250622201146-a16b152763fe/go.mod h1:A82XMVcq3XOiG9TpT+rt7/iYD5Eu87bxxmTk8O7F4cM= github.com/Bios-Marcel/wastebasket/v2 v2.0.3 h1:TkoDPcSqluhLGE+EssHu7UGmLgUEkWg7kNyHyyJ3Q9g= github.com/Bios-Marcel/wastebasket/v2 v2.0.3/go.mod h1:769oPCv6eH7ugl90DYIsWwjZh4hgNmMS3Zuhe1bH6KU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -152,8 +152,8 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6Yv go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -162,37 +162,35 @@ golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= -google.golang.org/genproto v0.0.0-20250519155744-55703ea1f237 h1:2zGWyk04EwQ3mmV4dd4M4U7P/igHi5p7CBJEg1rI6A8= -google.golang.org/genproto v0.0.0-20250519155744-55703ea1f237/go.mod h1:LhI4bRmX3rqllzQ+BGneexULkEjBf2gsAfkbeCA8IbU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 h1:IqsN8hx+lWLqlN+Sc3DoMy/watjofWiU8sRFgQ8fhKM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=