def get_slack(self, stage=None, ins=None, max_vectorial=None, ftol=None, lsb_scale=1): stage = copy.deepcopy(default(stage, self._start)) ins = self.default_ins(stage, ins) def system(x, scalar): return self.system(x, scalar, use_bands=True, sum_conf=True, lsb_scale=lsb_scale) system = self.limit_system(system, max_vectorial) tol = default(ftol, 1e-12) x_scale = 1e-3 x = self.map_in(stage, ins) xap, xan, xbp, xbn, xc = find_ab(system, x, x_scale, tol) resp = [ self.map_out(xap[ii:ii + 1, :])[0] for ii in range(np.size(xap, 0)) ] resn = [ self.map_out(xan[ii:ii + 1, :])[0] for ii in range(np.size(xan, 0)) ] return list(zip(resp, resn))
def save(self, path_context=None, data_location_override=None, memo=None): data_location = default(data_location_override, self.data_location) if data_location is None: result = self._to_json_dict() else: computed_path = data_location.computed_path save = memo is None or computed_path not in memo if save: if data_location.extension == "json": with open(computed_path, 'w') as f: json.dump(self._to_json_dict(), f) else: np.save(data_location.computed_path, self) if memo is not None: memo[computed_path] = self result = os.path.normpath( os.path.relpath(data_location.computed_path, path_context.computed_directory)) return result
def refine(self, start_stage=None, start_ins=None, n_iter=None, max_vectorial=None, lsb_scale=1): stage = copy.deepcopy(default(start_stage, self._start)) ins = self.default_ins(stage, start_ins) cm = stage.common_mode eff = stage.eff caps = stage.caps caps_off = np.size(cm) + np.size(eff) refs_off = caps_off + np.size(caps) norm_range = ( caps_off, refs_off, ) x = self.map_in(stage, ins) def system(x, scalar): return self.system(x, scalar, use_bands=True, sum_conf=True, lsb_scale=lsb_scale) system = self.limit_system(system, max_vectorial) x = refine(system, x, norm_range=norm_range, n_iter=n_iter) stage, ins = self.map_out([x]) return stage, ins
def __init__(self, data, x=None, axes_labels=None, style=None, title=None, subplot=( 1, 1, 1, ), plot_kwargs=None, **kwargs): super().__init__(**kwargs) if style is None: style = "plot" assert style in self.VALID_STYLES, "Invalid style recieved ({}).".format( style) self.plot_kwargs = default(plot_kwargs, {}) self.data = data self.x = x self.axes_labels = axes_labels self.title = title self.subplot = subplot self.style = style
def recreate_cache(eff, caps, refs, thres, ins, common_mode, c_seq, codes, scalar=None): fun = sims.Simulator scalar = default(scalar, len(np.shape(eff)) == 0) if scalar: codes = codes[:, np.newaxis, ...] data = fun.simulate_setup(eff, caps, refs, thres, ins, common_mode, c_seq, scalar=scalar) ext_dct = get(data, "extended")[0] eff, thres, cm = get(ext_dct, "eff", "thres", "cm") # shape (..., n_conf, n_diff,) seq_idx = fun.init_seq_idx(c_seq, data) set_data = None du_idx = None trans_idx = None sets_cache = [] cache = {"data": data, "seq_idx": seq_idx, "sets": sets_cache} for ii_set, c_set in enumerate(c_seq.configuration_sets): set_data = fun.init_set(c_set, data, set_data, du_idx) if set_data["previous"] is not None: ds_offset = data["ds_offset"] code = codes[ds_offset:ds_offset + 1, ...] trans_idx = fun.transition_step_idx(c_set, set_data, data, code) ds_offset = data["ds_offset"] code = codes[ds_offset:ds_offset + c_set.ds_samples, ...] du_idx = fun.du_indexes(code, c_set, set_data, data) sets_cache.append(( set_data, trans_idx, du_idx, )) return cache
def apply_save_pattern(self, pattern, path_context=None): path_context = default(path_context, PathContext.relative()) for ii, item in enumerate(self): path = pattern.format(ii) data_location = DataLocation.Parse(path, path_context, None_on_fail=False) if isinstance(item, IterableOfBase): item.set_children_data_location(data_location) else: item.data_location = data_location
def save(self, path_context=None, data_location_override=None, memo=None): data_location = default(data_location_override, self.data_location) contents = self.contents result = {"data": contents} if data_location is not None: with open(data_location.computed_path, 'w') as f: f.write(contents) result = os.path.normpath( os.path.relpath(data_location.computed_path, path_context.computed_directory)) return result
def refine(system, x, norm_range=None, n_iter=None, xtol=1e-8, ftol=None): tol_fact = 1.0 tol = ftol x_len = len(x) n_iter = default(n_iter, x_len * x_len) prev_x = x x_scale = 1e-1 norm = np.linalg.norm if ftol is None: tol = system(x, scalar=True).item() * tol_fact for ii in range(n_iter): print("-" * 30) print("Iter {}, tol: {}".format(ii, tol)) print("-" * 30) xap, xan, xbp, xbn, xc = find_ab(system, x, x_scale, tol) prev_x = x x = compute_movement(system, xap, xan, xbp, xbn, xc, tol) print(x_scale) print(x - prev_x) if REBUNDANT_CHECKS: assert system(x, scalar=True).item() - tol <= 0 if norm_range is not None: slc = slice(norm_range[0], norm_range[1]) x[slc] /= np.sum(x[slc]) if REBUNDANT_CHECKS: assert system(x, scalar=True).item() - tol <= 0 x_scale = 0.5 * (norm(xbp - x[np.newaxis, ...], axis=1) + norm(xbn - x[np.newaxis, ...], axis=1)) print("Tol before: {}".format(tol)) tol = min(tol, system(x, scalar=True).item() * tol_fact) print("Tol after : {}".format(tol)) if np.linalg.norm(x - prev_x) < xtol: print("xtol reached") break return x
def Parse(cls, path, path_context=None, None_on_fail=True): path_context = default(path_context, PathContext.relative()) if isinstance(path, str): directory, name_ext = os.path.split(path) dot_idx = name_ext.rfind('.') if dot_idx >= 0: name = name_ext[:dot_idx] ext = name_ext[dot_idx + 1:] else: name = name_ext ext = None return cls(path_context, directory, name, ext) else: if None_on_fail: return None else: raise ValueError("path is not a string.")
def run(args): n_bits = args.nbits n_refs = default(args.nrefs, 3) seed = None if args.seed is None else int(args.seed) meta = gen.StageMeta(args.nbits, n_refs, eff=args.eff, cap=args.cap, common_mode=args.common_mode, fsr=( args.min, args.max, ), differential=args.differential, seed=seed) data_location = data.DataLocation(data.PathContext.relative(), args.location, args.dest, "json") print(" saving {}...".format(data_location.computed_path)) data.save(meta, data_location)
def save(self, path_context=None, data_location_override=None, memo=None): data_location = default(data_location_override, self.data_location) if data_location is None: result = self._to_json_dict(path_context, memo=memo) else: computed_path = data_location.computed_path save = memo is None or computed_path not in memo local_path_context = data_location.as_path_context() if save: with open(computed_path, 'w') as f: dct = self._to_json_dict(local_path_context, memo=memo) json.dump(dct, f, indent=2) if memo is not None: memo[computed_path] = self result = os.path.normpath( os.path.relpath(data_location.computed_path, path_context.computed_directory)) return result
def __init__(self, start_stage, configuration_sequence, codes, mask=None, sum_conf=False, use_bands=False): assert isinstance( configuration_sequence, gen.ConfigurationSequence), "Check scalar testbench is being used." assert isinstance( start_stage, gen.StageParameters), "Check scalar testbench is being used." self._start = start_stage self._codes = codes self._configuration_sequence = configuration_sequence self._mask = default(mask, {}) assert all(key in self.MASK_KEYS for key in self._mask.keys()) self.sum_conf = sum_conf self.use_bands = use_bands
def snr(adc_real, adc_assumed=None, sampling_factor=16): """ Computes the signal to noise ratio (SNR) of an ADC. The output is in absolute magnitude (not decibels or bits). :param adc_real: Adc to be simulated :type n_caps: :class:`gen.PipeParameters` :param adc_assumed: Parameters used to calibrate the conversion, None to assume perfect knowledge. :type adc_assumed: :class:`gen.PipeParameters` :param sampling_factor: The number of samples used to calculate the SNR is `(2**adc_n_bits + 1) * sampling_factor`, more samples increases precision. :type sampling_factor: :class:`int` :returns: The signal to noise ratio of the adc assuming its parameters, in absoulte magnitude. :rtype: :class:`float` """ adc_assumed = default(adc_assumed, adc_real) assert all(real.meta == assumed.meta for real, assumed in zip(adc_real.stages, adc_assumed.stages)) assert len(adc_real.stages) == len(adc_assumed.stages) assert np.size(adc_real.tail) == np.size(adc_assumed.tail) tot_bits = ( sum([stage.meta.n_bits for stage in adc_real.stages]) + int(np.log2(np.size(adc_real.tail))) ) samples = int((2**tot_bits + 1) * sampling_factor) original_signal = np.linspace(*adc_real.stages[0].meta.fsr, samples) conversion, tail_code = adc_real.convert(original_signal[..., np.newaxis]) converted_signal = adc_assumed.rebuild(conversion, tail_code) signal_power = np.power(original_signal - np.mean(original_signal), 2) error_power = np.power(original_signal - converted_signal, 2) return np.sum(signal_power) / np.sum(error_power)
def __deepcopy__(self, memo=None): memo = default(memo, {}) return JsonIterable( tuple(copy.deepcopy(ee, memo=memo) for ee in self))
def simulate(self, eff, caps, refs, thres, ins, common_mode, c_seq, scalar=None, raise_=False): scalar = default(scalar, len(np.shape(eff)) == 0) meta = c_seq.meta data = self.simulate_setup(eff, caps, refs, thres, ins, common_mode, c_seq, scalar=scalar) self._standard_deviations(meta, data) idx_dct, ext_dct, n_dct = get(data, "indexing", "extended", "n") eff, thres, cm = get(ext_dct, "eff", "thres", "cm") n_diff = get(n_dct, "n_diff")[0] u_history = [] with self._random_state as _: # shape (..., n_conf, n_diff,) seq_idx = self.init_seq_idx(c_seq, data) u = self.init_seq(seq_idx, data) if self.u_history: u_history.append(u) # Simulate each configuration set codes = [] du_idx = None set_data = None n_sets = len(c_seq.configuration_sets) for ii_set, c_set in enumerate(c_seq.configuration_sets): set_data = self.init_set(c_set, data, set_data, du_idx) if set_data["previous"] is not None: code = self.u_thres_to_code(u[-1, ...], thres, data) code = code[np.newaxis, ...] trans_idx = self.transition_step_idx( c_set, set_data, data, code) u = self.transition_step(trans_idx, u[-1:, ...], set_data, data) codes.append(code) if self.u_history: u_history.append(u) for sample in range(c_set.ds_samples): # print(" {}/{} Sample {}/{} ({:0.2f}%)".format( # ii_set+1, n_sets, sample+1, c_set.ds_samples, 100*sample/c_set.ds_samples), # end='\r') code = self.u_thres_to_code(u[-1, ...], thres, data) code = code[np.newaxis, ...] codes.append(code) du_idx = self.du_indexes(code, c_set, set_data, data) # used in u du = self.du_compute(du_idx, c_set, set_data, data) u = ne.evaluate("u*eff + (1-eff)*cm + du") # common mode feedback if n_diff == 2: u += cm[np.newaxis, ...] - np.mean( u, axis=-1, keepdims=True) if self.u_history: u_history.append(u) codes = np.concatenate(codes, axis=0) if self.u_history: u_history = np.concatenate(u_history, axis=0) if scalar: assert np.size(codes, 1) == 1 assert np.size(u_history, 1) == 1 codes = codes[:, 0, ...] u_history = u_history[:, 0, ...] if ((u_history < meta.fsr[0] - meta.lsb).any() or (u_history > meta.fsr[1] + meta.lsb).any()): message = "Residual out of range." if raise_: raise ValueError(message) else: warnings.warn(message) return codes, u_history
def load(data_class, data_location, memo=None): memo = default(memo, {}) return data_class.Load(data_location.path_context, data_location.filepath, memo)
def save(data, data_location_override=None, memo=None): memo = default(memo, {}) path_context = PathContext.relative() return data.save(path_context, data_location_override, memo=memo)
def __init__(self, stages, ins, configuration_sequence, shape=None, data_location=None): super().__init__(data_location) NestedStages = data.nested_lists_of(gen.StageParameters) NestedSequences = data.nested_lists_of(gen.ConfigurationSequence) if not isinstance(configuration_sequence, NestedSequences): conf_shape = np.shape(configuration_sequence) configuration_sequence = NestedSequences(configuration_sequence, len(conf_shape)) conf_shape = np.shape(configuration_sequence.data) if not isinstance(stages, NestedStages): shape = default(shape, np.shape(stages)) dims = len(shape) cur = stages root_arr = stages # Check a valid 0,0,0... for dd in range(dims): assert isinstance(cur, ( tuple, list, )) cur = cur[0] # Check elements for idx in cartesian(*tuple(range(ss) for ss in shape)): assert isinstance(misc.getitem(stages, idx), gen.StageParameters) # Check regularity def rec_check(lst, shape): valid = (not isinstance(lst, list) and len(shape) == 0) or len(lst) == shape[0] if len(shape) > 1: sub_shape = shape[1:] valid = valid and all( [rec_check(llst, sub_shape) for llst in lst]) return valid assert rec_check(stages, shape) else: stages_shape = np.shape(stages.data) shape = default(shape, stages_shape) assert shape == stages_shape dims = len(shape) root_arr = stages.data ref_element = misc.getitem(root_arr, (0, ) * dims) ins = data.at_least_ndarray(ins) if len(np.shape(ins)) == 1: ins = ins[..., np.newaxis] # Broadcast ins if len(np.shape(ins)) == 2: ins = ins[(np.newaxis, ) * dims + (Ellipsis, )] ins = np.tile(ins, shape + ( 1, 1, )) assert len(np.shape(ins)) == dims + 2 if np.size(ins, -1) != ref_element.meta.n_diff: cm = ref_element.meta.common_mode ins = np.concatenate(( cm - ins, cm + ins, ), axis=1) # All meta the same for idx in cartesian(*tuple(range(ss) for ss in shape)): c_element = misc.getitem(root_arr, idx) assert c_element.meta == ref_element.meta self._stages = NestedStages.EnsureIsInstance(stages) self._shape = shape self._ins = ins self._configuration_sequence = configuration_sequence
def system(self, x, scalar=False, use_bands=None, sum_conf=None, limit_samples=None, lsb_scale=1): if scalar: x = [x] cm, eff, caps, refs, thres, ins = self._map_internal(x) ext_codes = self._codes[:, np.newaxis, ...] if not hasattr(self, "_cache"): self._cache = {} base_shape = np.shape(x)[:-1] if base_shape not in self._cache: print("Generating cache for {}".format(base_shape)) self._cache[base_shape] = self.recreate_cache( eff, caps, refs, thres, ins, cm, self._configuration_sequence, ext_codes) use_bands = default(use_bands, self.use_bands) sum_conf = default(sum_conf, self.sum_conf) ext_codes = self._codes[:, np.newaxis, ...] u = self.recreate(eff, caps, refs, thres, ins, cm, self._configuration_sequence, self._cache[base_shape], limit_samples=limit_samples) meta = self._configuration_sequence.meta # Ignore last u since it is not converted to code u = np.diff(u[:-1, :, ...], axis=-1) if meta.differential else u[:-1, :, ..., -1] samples = np.size(u, 0) u_center, lsb = self._compute_u_center(thres) thres_bits, thres_half = gen.infer_thres_bits(thres[0, ...]) ideal_lsb = gen.compute_lsb(thres_bits, *self._start.meta.fsr, thres_half) lsb = lsb + ideal_lsb * (lsb_scale - 1) if use_bands else np.zeros(( samples, 1, 1, )) result = np.maximum( np.abs(u - u_center[:samples, ...]) - lsb[:samples, ...] / 2, 0) if DEBUG: # FIXME import matplotlib.pyplot as plots try: print(np.shape(result)) sum_axis = tuple(range(len(np.shape(result)) - 1)) cut = (np.sum(result, axis=sum_axis) > 0).tolist().index(True) print("Found cut {}".format(cut)) except: cut = 10 print("Not found cut") x_thres = np.stack(( np.zeros_like(thres[0, :]), np.full_like(thres[0, :], samples), ), axis=0) y_thres = np.stack((thres[0, :], ) * 2, axis=0) plots.plot(x_thres, y_thres, c='orange', linestyle='-.') plots.plot(u[:, 0, cut, ...], 'r') internal, _ = self.configuration_sequence.configuration_sets[ 0].generate_in(self.configuration_sequence. configuration_sets[0].ds_samples) internal = np.sum(internal, axis=( -2, -1, )) plots.plot(0.25 * (internal[:, cut, ...] - 1.5), 'cyan') #plots.plot(internal[:samples, cut, ...], 'k') adj_codes = (0.5 / (np.max(self._codes))) * (self._codes - np.max(self._codes) / 2) plots.plot(adj_codes[:samples, cut, ...], 'k') plots.plot(u_center[:samples, 0, cut, ...], 'b') plots.plot(u_center[:samples, 0, cut, ...] + lsb[:samples, 0, cut, ...] / 2, 'g', linestyle='--') plots.plot(u_center[:samples, 0, cut, ...] - lsb[:samples, 0, cut, ...] / 2, 'g', linestyle='--') plots.show() if scalar: result = result[:, 0, ...] else: result = np.transpose(result, ( 1, 0, ) + tuple(range(2, len(np.shape(result))))) sum_axis = ( -2, -1, ) if sum_conf else (-2, ) result = np.sum(result, axis=sum_axis) if PRINT_ERROR: print("System error: {}".format(np.sum(np.power(result, 2)))) return result
def calib(meta, args, interlace, use_full_range=None): n_caps = meta.n_caps n_refs = meta.n_refs n_diff = meta.n_diff n_cs = (n_caps - 1) // 2 n_cf = n_caps - n_cs use_full_range = misc.default(use_full_range, n_cs < 2) ds_samples = args.samples if args.n_test > 0: raise ValueError("Minimal does not support test inputs.") comb_cs = misc.iterate_combinations(n_caps, n_cs) if args.full: comb_cs = [tuple(misc.iterate_permutations(cs)) for cs in comb_cs] comb_cs = [elem for tlp in comb_cs for elem in tlp] slice_ = slice(None) if use_full_range else slice(1, -1) comb_refs = gen.ds_map(n_cs, n_refs, n_cs * (n_refs - 1) + 1) comb_refs = np.transpose(comb_refs[:, slice_], ( 1, 0, 2, )) comb_refs = comb_refs.tolist() comb_refs = [( comb_refs[ii], comb_refs[jj], ) for ii in range(len(comb_refs)) for jj in range(ii + 1, len(comb_refs))] comb_cs = list(comb_cs) comb_refs = list(comb_refs) even_configs = [] even_ins = [] ics = [] with misc.push_random_state(): seed = None if args.seed is None else int(args.seed) np.random.seed(seed) for cs_ii, refs_ii in cartesian(comb_cs, comb_refs): even_configs.append(gen.Configuration(meta, cs_ii)) top_ii, bot_ii = refs_ii if args.inputs == "": sub_seed = np.random.randint(0, 4294967296) even_ins.append( gen.InternalRandom(meta, np.size(cs_ii), sub_seed)) else: top = gen.InternalDC(meta, top_ii) bot = gen.InternalDC(meta, bot_ii) even_ins.append(gen.ACCombinator(meta, top, bot, args.period)) inv = [[n_refs - 1 - iii for iii in ii] for ii in top_ii] inv = inv + [[n_refs // 2, n_refs - n_refs // 2][:n_diff] ] * (n_cf - n_cs) ics.append(gen.InitialCondition(meta, inv)) if interlace: n_cs_h = n_cs // 2 assert n_cs_h > 0, "Not enough capacitors to decrease bits." odd_configs = [] odd_ins = [] for conf, in_ in zip(even_configs, even_ins): left = (n_cs - n_cs_h) // 2 cs_range = range(left, left + n_cs_h) mask = np.zeros((n_cs, ), dtype=bool) mask[cs_range] = 1 odd_configs.append( gen.Configuration(conf.meta, conf.cs[cs_range, :])) odd_ins.append(gen.InputMask(in_.meta, in_, mask)) else: odd_ins = even_ins odd_configs = even_configs conf_sets = [] parity = 0 for samples in ds_samples: if parity == 0: configs = even_configs inputs = even_ins else: configs = odd_configs inputs = odd_ins conf_sets.append(gen.ConfigurationSet(samples, inputs, configs)) parity = (parity + 1) % 2 if args.ic == "clear": ics = [gen.InitialCondition.Discharged(meta, n_cf)] * len(odd_ins) elif args.ic == "precharge": pass else: raise ValueError("ic type {} not supported".format(args.ic)) return gen.ConfigurationSequence(ics, conf_sets * args.loop)
def recreate(eff, caps, refs, thres, ins, common_mode, c_seq, cache, scalar=None, limit_samples=None): fun = sims.Simulator scalar = default(scalar, len(np.shape(eff)) == 0) limit_samples = default(limit_samples, c_seq.samples) + 1 samples = 0 cache = dict(cache) cache["data"] = fun.simulate_setup(eff, caps, refs, thres, ins, common_mode, c_seq, scalar=scalar) data = cache["data"] seq_idx = cache["seq_idx"] u_history = [] # shape (..., n_conf, n_diff,) u = fun.init_seq(seq_idx, data) u_history.append(u) samples += 1 # Simulate each configuration set dct_idx, dct_ext, dct_n = get(data, "indexing", "extended", "n") n_conf, n_diff = get(dct_n, "n_conf", "n_diff") eff, cm = get(dct_ext, "eff", "cm") base_shape, base_len = get(dct_idx, "base_shape", "base_len") c_sets = c_seq.configuration_sets def multi_idx_filter(idx_tuple, sub_idx): return tuple(ii[sub_idx] if hasattr(ii, "__getitem__") else ii for ii in idx_tuple) for ii_set, c_set, data_trans_du in zip(range(len(c_sets)), c_sets, cache["sets"]): set_data, trans_idx, du_idx = data_trans_du if set_data["previous"] is not None: u = fun.transition_step(trans_idx, u[-1:, ...], set_data, data) u_history.append(u) samples += 1 r_du = (1 - eff) * cm n_u = np.empty((c_set.ds_samples, ) + base_shape + ( n_conf, n_diff, )) local_du_idx = dict(du_idx) # used in u du = fun.du_compute(du_idx, c_set, set_data, data) for idx in cartesian(*tuple(range(ss) for ss in base_shape)): local_idx = tuple(slice(ii, ii + 1) for ii in idx) + (Ellipsis, ) ext_local_idx = (slice(None), ) + local_idx local_du_idx["r_ref"] = local_du_idx["r_ref"][ext_local_idx] local_du_idx["m_in_ref"] = multi_idx_filter( local_du_idx["m_in_ref"], ext_local_idx) local_du_idx["m_in_ins"] = multi_idx_filter( local_du_idx["m_in_ins"], ext_local_idx) zi = u[(slice(-1, None), ) + local_idx] * eff[local_idx] local_u = lfilter([1], [1, -eff[local_idx].item()], du[ext_local_idx] + r_du[(np.newaxis, ) + local_idx], zi=zi, axis=0)[0] n_u[ext_local_idx] = local_u u = n_u u_history.append(u) samples += np.size(u, 0) if samples >= limit_samples: break u_history = np.concatenate(u_history, axis=0) u_history = u_history[:limit_samples, ...] if scalar: assert np.size(u_history, 1) == 1 u_history = u_history[:, 0, ...] return u_history
def run_calibration(self, start_stage=None, start_ins=None, n_switches=5, switching_nfev=30, samples_step=512, lsb_scale=1): stage = copy.deepcopy(default(start_stage, self._start)) ins = self.default_ins(stage, start_ins) x = self.map_in(stage, ins) bounds = self.bounds(ins) nfev = switching_nfev steps = self._configuration_sequence.samples // samples_step steps = [ss * samples_step for ss in range(1, steps)] + [None] for limit_samples in steps: res = Namespace() res.cost = 1 for try_ in range(n_switches): if res.cost == 0: break print(" No bands, no bounds {}/{}, limit {}".format( try_ + 1, n_switches, limit_samples)) res = least_squares( lambda x: self.system(x, scalar=True, use_bands=False, limit_samples=limit_samples, lsb_scale=lsb_scale), x, max_nfev=nfev, verbose=2) # FIXME: verbose x = res.x # Clip x = [ max(min(xx, M), m) for xx, m, M in zip(x, bounds[0], bounds[1]) ] print(" Bands {}/{}, limit {}".format(try_ + 1, n_switches, limit_samples)) res = least_squares( lambda x: self.system(x, scalar=True, use_bands=True, limit_samples=limit_samples, lsb_scale=lsb_scale), x, bounds=bounds, max_nfev=nfev, verbose=2) # FIXME: verbose #x, max_nfev=nfev, verbose=2) # FIXME: bounds x = res.x if res.cost != 0: print(" Final no bounds") res = least_squares( lambda x: self.system(x, scalar=True, use_bands=True, limit_samples=limit_samples, lsb_scale=lsb_scale), x, verbose=2) # FIXME: verbose x = res.x # Clip x = [ max(min(xx, M), m) for xx, m, M in zip(x, bounds[0], bounds[1]) ] print(" Final") res = least_squares( lambda x: self.system(x, scalar=True, use_bands=True, limit_samples=limit_samples, lsb_scale=lsb_scale), x, bounds=bounds, verbose=2) # FIXME: verbose x = res.x stage, ins = self.map_out([x]) return stage, ins