@@ -44,6 +44,9 @@ func NewWriter(filename string) (*Writer, error) {
4444// appropriate HDF5 datatype and written as a dataset. A MATLAB_class
4545// attribute is added to indicate the MATLAB type.
4646//
47+ // For complex numbers, a group structure is created with nested real/imag datasets
48+ // and appropriate MATLAB_class and MATLAB_complex attributes.
49+ //
4750// Parameters:
4851// - v: Variable to write (must not be nil)
4952//
@@ -52,7 +55,7 @@ func NewWriter(filename string) (*Writer, error) {
5255//
5356// Supported types:
5457// - Double, Single, Int8, Uint8, Int16, Uint16, Int32, Uint32, Int64, Uint64
55- // - Complex numbers (future implementation )
58+ // - Complex numbers (stored as HDF5 groups with /real and /imag datasets )
5659func (w * Writer ) WriteVariable (v * types.Variable ) error {
5760 // Check for nil first
5861 if v == nil {
@@ -64,7 +67,7 @@ func (w *Writer) WriteVariable(v *types.Variable) error {
6467 return fmt .Errorf ("invalid variable: %w" , err )
6568 }
6669
67- // Handle complex numbers separately (future implementation )
70+ // Handle complex numbers separately (group structure with nested datasets )
6871 if v .IsComplex {
6972 return w .writeComplexVariable (v )
7073 }
@@ -124,16 +127,14 @@ func (w *Writer) writeSimpleVariable(v *types.Variable) error {
124127 return nil
125128}
126129
127- // writeComplexVariable writes complex variable (real + imaginary) .
130+ // writeComplexVariable writes complex variable in proper MATLAB v7.3 format .
128131//
129- // WORKAROUND: Due to HDF5 library limitations, complex numbers are stored as
130- // two separate datasets at root level:
131- // - varname_real: real part
132- // - varname_imag: imaginary part
132+ // MATLAB v7.3 stores complex numbers as HDF5 groups with nested datasets:
133+ // - /varname (group with MATLAB_class and MATLAB_complex attributes)
134+ // - /real (dataset containing real part)
135+ // - /imag (dataset containing imaginary part)
133136//
134- // Standard MATLAB format uses groups (/varname/real, /varname/imag), but the
135- // HDF5 library doesn't yet support nested datasets or group attributes.
136- // See: docs/dev/notes/BUG_REPORT_HDF5_GROUP_ATTRIBUTES.md.
137+ // This matches the standard MATLAB format specification for HDF5-based .mat files.
137138func (w * Writer ) writeComplexVariable (v * types.Variable ) error {
138139 // Extract real and imaginary parts
139140 numArray , ok := v .Data .(* types.NumericArray )
@@ -160,44 +161,45 @@ func (w *Writer) writeComplexVariable(v *types.Variable) error {
160161 return fmt .Errorf ("unsupported data type: %w" , err )
161162 }
162163
163- // Create real dataset (flat structure workaround)
164- realName := v .Name + "_real"
165- realDataset , err := w .file .CreateDataset ("/" + realName , hdf5Type , dims )
164+ // Step 1: Create group for variable
165+ group , err := w .file .CreateGroup ("/" + v .Name )
166166 if err != nil {
167- return fmt .Errorf ("failed to create real dataset: %w" , err )
168- }
169-
170- // Write real data
171- if err := realDataset .Write (numArray .Real ); err != nil {
172- return fmt .Errorf ("failed to write real data: %w" , err )
167+ return fmt .Errorf ("failed to create group for complex variable: %w" , err )
173168 }
174169
175- // Add MATLAB_class attribute to real dataset
170+ // Step 2: Write MATLAB metadata to group
176171 matlabClass := w .dataTypeToMatlabClass (v .DataType )
177- if err := realDataset .WriteAttribute ("MATLAB_class" , matlabClass ); err != nil {
172+ if err := group .WriteAttribute ("MATLAB_class" , matlabClass ); err != nil {
178173 return fmt .Errorf ("failed to write MATLAB_class attribute: %w" , err )
179174 }
180175
181- // Create imaginary dataset (flat structure workaround)
182- imagName := v .Name + "_imag"
183- imagDataset , err := w .file .CreateDataset ("/" + imagName , hdf5Type , dims )
176+ // MATLAB_complex attribute indicates this is a complex number
177+ if err := group .WriteAttribute ("MATLAB_complex" , uint8 (1 )); err != nil {
178+ return fmt .Errorf ("failed to write MATLAB_complex attribute: %w" , err )
179+ }
180+
181+ // Step 3: Create nested datasets for real/imag parts
182+ realPath := "/" + v .Name + "/real"
183+ imagPath := "/" + v .Name + "/imag"
184+
185+ realDataset , err := w .file .CreateDataset (realPath , hdf5Type , dims )
184186 if err != nil {
185- return fmt .Errorf ("failed to create imaginary dataset: %w" , err )
187+ return fmt .Errorf ("failed to create real dataset: %w" , err )
186188 }
187189
188- // Write imaginary data
189- if err := imagDataset . Write ( numArray . Imag ); err != nil {
190- return fmt .Errorf ("failed to write imaginary data : %w" , err )
190+ imagDataset , err := w . file . CreateDataset ( imagPath , hdf5Type , dims )
191+ if err != nil {
192+ return fmt .Errorf ("failed to create imaginary dataset : %w" , err )
191193 }
192194
193- // Add MATLAB_class attribute to imaginary dataset
194- if err := imagDataset . WriteAttribute ( "MATLAB_class" , matlabClass ); err != nil {
195- return fmt .Errorf ("failed to write MATLAB_class attribute : %w" , err )
195+ // Step 4: Write data
196+ if err := realDataset . Write ( numArray . Real ); err != nil {
197+ return fmt .Errorf ("failed to write real data : %w" , err )
196198 }
197199
198- // Note: MATLAB_complex attribute would normally indicate this is a complex variable,
199- // but HDF5 library has issues writing multiple attributes.
200- // The _real/_imag suffix is sufficient for identification.
200+ if err := imagDataset . Write ( numArray . Imag ); err != nil {
201+ return fmt . Errorf ( "failed to write imaginary data: %w" , err )
202+ }
201203
202204 return nil
203205}
0 commit comments