From 333c6b1e86c750cf6991753a024db035a585b044 Mon Sep 17 00:00:00 2001
From: Maxim Gonchar <maxim.mg.gonchar@gmail.com>
Date: Mon, 24 Apr 2023 17:18:07 +0300
Subject: [PATCH] Squashed 'subtrees/dagflow/' changes from
 13ed95968..ded618f19

ded618f19 Merge commit 'e7b96a00757d12725312475678fdaab7d00f0ae8' into feature/pars-gindex
e7b96a007 Squashed 'subtrees/gindex/' changes from e424e30..7653a77
352a7ce3e feat: `load_parameters` add `replicate` option

git-subtree-dir: subtrees/dagflow
git-subtree-split: ded618f1935a2a8fa8900b5ab30bbed02def3d14
---
 dagflow/bundles/load_parameters.py | 39 ++++++++++++++++++------------
 subtrees/gindex/gindex/gnindex.py  |  4 +++
 2 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/dagflow/bundles/load_parameters.py b/dagflow/bundles/load_parameters.py
index dda5f27..f0b496a 100644
--- a/dagflow/bundles/load_parameters.py
+++ b/dagflow/bundles/load_parameters.py
@@ -64,12 +64,15 @@ def IsFormatOk(format):
         return f1 in ('value', 'central')
 
 IsFormat = Schema(IsFormatOk, error='Invalid parameter format "{}".')
+IsStrSeq = (str,)
+IsStrSeqOrStr = Or(IsStrSeq, And(str, Use(lambda s: (s,))))
 IsParsCfgDict = Schema({
     'parameters': IsValuesDict,
     'labels': IsLabelsDict,
     'format': IsFormat,
     'state': Or('fixed', 'variable', error='Invalid parameters state: {}'),
-    Optional('path', default=''): str
+    Optional('path', default=''): str,
+    Optional('replicate', default=((),)): (IsStrSeqOrStr,),
     },
     # error = 'Invalid parameters configuration: {}'
 )
@@ -197,22 +200,26 @@ def load_parameters(acfg):
         sep='.'
     )
 
+    subkeys = cfg['replicate']
+
     normpars = []
-    for key, varcfg in iterate_varcfgs(cfg):
-        skey = '.'.join(key)
-        label = varcfg['label']
-        label['key'] = skey
-        label.setdefault('text', skey)
-
-        varcfg.setdefault(state, True)
-
-        par = Parameters.from_numbers(**varcfg)
-        if par.is_constrained:
-            target = ('constrained', path)
-        elif par.is_fixed:
-            target = ('constant', path)
-        else:
-            target = ('free', path)
+    for key_general, varcfg in iterate_varcfgs(cfg):
+        for subkey in subkeys:
+            key = key_general + subkey
+            key_str = '.'.join(key)
+            label = varcfg['label']
+            label['key'] = key_str
+            label.setdefault('text', key_str)
+
+            varcfg.setdefault(state, True)
+
+            par = Parameters.from_numbers(**varcfg)
+            if par.is_constrained:
+                target = ('constrained', path)
+            elif par.is_fixed:
+                target = ('constant', path)
+            else:
+                target = ('free', path)
 
         ret[('parameter_node',)+target+key] = par
 
diff --git a/subtrees/gindex/gindex/gnindex.py b/subtrees/gindex/gindex/gnindex.py
index 3a4e955..adf7e66 100644
--- a/subtrees/gindex/gindex/gnindex.py
+++ b/subtrees/gindex/gindex/gnindex.py
@@ -503,6 +503,10 @@ class GNIndex:
         """Returns the dimension of the index (size of the indices list)"""
         return len(self._indices)
 
+    @property
+    def values(self) -> Tuple[Tuple[str]]:
+        return tuple(n.values for n in self)
+
     def instances(self) -> Tuple[Tuple[GNIndexInstance, ...], ...]:
         """Returns a tuple of the indices instances tuples (2D version)"""
         return tuple(ind.instances() for ind in self._indices)
-- 
GitLab