Compare commits

...

6 commits

Author SHA1 Message Date
200b1eb572 Parameters: handle simple Scales
- build a default value
 - handle cyclic scales
 - implement clamping behaviour
 - identify a muliplicative factor
 - join a feed either multiplicative or additive
2026-09-12 01:16:16 +02:00
4e4222ebc7 Parameters: mark out the base operations of a Scale
Scales are defined as descriptor records and will be used as const.
Besides some information functions, a Scale
 * allows to conform a value to be compliant with the Scale's constraints
 * can ''join'' and thus apply a ''feed'' on top of a ''base value'';
   this is the foundation for applying an automation function, while
   handling multiplicative and logarithmic cases properly
2026-09-12 00:39:11 +02:00
50ef9dd985 Parameters: in-depth analysis regarding Scale parameters
Notably I considered how and to what extent we will need to represent ''nominal'' or ''ordinal scales''...
In fact we should represent them, yet as cascaded delegate, since that is a relevant topic,
yet not the primary use case -- and a topic with very deep complexity in itself.
2026-09-11 01:44:48 +02:00
4a138f7383 Parameters: consider what to conceptualise as a Scale
It is clear by now that a `Scale` will act as a refinement of a full-domain value type.
However, in order to develop the definition and builder notation for parameters,
a much more detailed understanding of scales is necessary -- including the question
where to draw a line between the complex structured `ParamSet` and a simple
`Parameter` that is conceived to be number-value-like.
2026-08-10 01:28:41 +02:00
87ce59da29 Parameters: sketch a prototype-builder API
...yet the actual problem remains that the value type of the
prototype remains a runtime-dynamic hidden implementation trait.

How can we remould the scale hidden within a parameter, while
in the regular setup, the scale is implemented as an immutable
entry placed into a registry?
2026-09-06 01:39:09 +02:00
8de5a4b475 Parameters: mapping out the next steps to draft
...I do ''not intend to go into a parameter deep-dive'' yet,
but I want to set out the basic capabilities to be expected...
2026-09-06 00:50:53 +02:00
9 changed files with 1707 additions and 50 deletions

View file

@ -27,9 +27,9 @@
** mostly at start and then hold and use the memory, the allocation is never
** actually _closed_ — implying that further allocations can be added during
** the whole life time, which may possibly even trigger a further base allocation
** if storage space in the last Extent is exhausted. In theory, it would be possible
** if storage space if the last Extent is exhausted. In theory, it would be possible
** to use a custom allocation (in the AllocationCluster::StorageManager::Extents,
** which is a lib::LinkedElements and could be parametrised with a allocator template).
** which is a lib::LinkedElements and could be parametrised with an allocator template).
** Allocations are never discarded, and thus any alloted memory will be kept until
** the whole AllocationCluster is destroyed as a compound.
** \par using as STL allocator

53
src/lib/par/nom-set.hpp Normal file
View file

@ -0,0 +1,53 @@
/*
NOM-SET.hpp - nominal scale domain
Copyright (C)
2026 Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
*/
/** @file nom-set.hpp
** Collection of identifiers to constitute the domain for a nominal or ordinal scale.
** The scale descriptor is used as delegate from the ParamType descriptor and maintained
** within a global registry for sake of deduplication. It is expected that a lot of parameters
** will share some common scales, like e.g. percentage values or decibels. The setup of a scale
** may limit the value range, provide hints for the UI representation -- yet may possibly also
** encompass nominal scales that comprise a selection of ID values.
**
** @todo WIP-WIP-WIP can be considered an initial draft and placeholder, as of 2026
*/
#ifndef LIB_PAR_NOM_SET_H
#define LIB_PAR_NOM_SET_H
#include "lib/par/spec.hpp"
namespace lib {
namespace par {
/**
* Interface: describe the properties of a value scale to use for parameters,
* including range limits and metric (linear, logarithmic). The core operation
* is to conform a value to this specific scale.
* @todo not clear if we want a virtual interface here....?
*/
class NomSet
{
public:
};
}} // namespace lib::par
#endif /*LIB_PAR_NOM_SET_H*/

View file

@ -58,9 +58,6 @@ namespace par {
: protected ParamContainer
{
public:
template<typename VAL>
class Builder;
template<typename VAL>
VAL getVal() const;
@ -69,6 +66,9 @@ namespace par {
/* === Builder API === */
template<typename VAL>
class Builder;
template<typename VAL>
static Builder<VAL>
forType() { return {}; }
@ -82,6 +82,8 @@ namespace par {
.withValue (std::forward<VAL> (initVal));
}
class ProtoBuilder;
static ProtoBuilder from (Parameter const& prototype);
protected:
template<class IMP, typename...ARGS>
@ -111,13 +113,45 @@ namespace par {
withValue (X&& initVal)
{
initVal_ = std::forward<X> (initVal);
return std::move(this);
return std::move(*this);
}
};
class Parameter::ProtoBuilder
{
Parameter ref_;
public:
ProtoBuilder (Parameter const& prototype)
: ref_{prototype}
{ }
Parameter
build()
{
return ref_;
}
template<typename X>
ProtoBuilder&&
maxVal (X&& upperBound)
{
/////////////////////////////////////////////OOO how to remould a scale?
return std::move(*this);
}
};
inline Parameter::ProtoBuilder
Parameter::from (Parameter const& prototype)
{
return ProtoBuilder{prototype};
}
template<typename VAL>
VAL
inline VAL
Parameter::getVal() const
{
static_assert (isBaseType<VAL>, "only preconfigured parameter BaseTypes are supported");
@ -127,7 +161,7 @@ namespace par {
template<typename VAL>
void
inline void
Parameter::setVal (VAL&& changedVal)
{
static_assert (isBaseType<VAL>, "only preconfigured parameter BaseTypes are supported");

View file

@ -1,5 +1,5 @@
/*
PARAM-TYPE.hpp - value scale to use for parameters
SCALE.hpp - value scale to use for parameters
Copyright (C)
2026 Hermann Vosseler <Ichthyostega@web.de>
@ -29,26 +29,168 @@
#include "lib/par/domain.hpp"
#include "lib/util.hpp"
#include <optional>
namespace lib {
namespace par {
using std::optional;
enum Metric {LIN ///< linear ordinary numeric scale
,BIN ///< binary logarithm
,NAT ///< natural logarithm
,DEC ///< decibels (1/10 of 10-based log)
,NOM ///< value encodes a nominal or ordinal scale
};
/**
* Interface: describe the properties of a value scale to use for parameters,
* including range limits and metric (linear, logarithmic). The core operation
* is to conform a value to this specific scale.
* @todo not clear if we want a virtual interface here....?
*/
template<typename VAL>
class Scale
{
public:
virtual ~Scale(); ///< this is an interface
Metric metric{LIN};
/////////////////////////////OOO Quantiser?
optional<VAL> minVal{};
optional<VAL> maxVal{};
optional<VAL> minUse{};
optional<VAL> maxUse{};
optional<VAL> neutral{};
optional<VAL> defVal{};
/////////////////////////////OOO »Sentinels« and nominal scales?
bool cyclic{false};
/* ===== information functions ===== */
bool isValid() const;
bool isFactor() const;
/* ===== conforming operations ===== */
VAL getDefault() const;
VAL conform (VAL const&) const;
template<typename SRC>
VAL join (VAL const&, SRC const&, Scale<SRC> const&) const;
VAL join (VAL const&, VAL const&) const;
};
/* ===== information functions ===== */
/** self consistency check */
template<typename VAL>
inline bool
Scale<VAL>::isValid() const
{
return ((not minVal or not maxVal)
or *minVal <= *maxVal
)
and (not minUse
or (not minVal or *minVal <= *minUse)
)
and (not maxUse
or (not maxVal or *maxUse <= *maxVal)
)
and ((not minUse or not maxUse)
or *minUse <= *maxUse
)
and (not neutral
or ( (not maxVal or *neutral <= *maxVal)
and (not minVal or *minVal <= *neutral)
)
)
and (not defVal
or ( (not maxVal or *defVal <= *maxVal)
and (not minVal or *minVal <= *defVal)
)
)
and (not cyclic
or (minVal and maxVal and *minVal < *maxVal)
)
;
}
template<typename VAL>
inline bool
Scale<VAL>::isFactor() const
{
return metric == LIN
and neutral
and *neutral == VAL(1);
}
/* ===== conforming operations ===== */
/** Build initial value that fits into the scale. */
template<typename VAL>
inline VAL
Scale<VAL>::getDefault() const
{
return defVal? *defVal
: neutral? *neutral
: conform (VAL{});
}
/**
* Accommodate a raw value from the underlying domain,
* so that it conforms with this Scale definition.
*/
template<typename VAL>
inline VAL
Scale<VAL>::conform (VAL const& rawVal) const
{
if (cyclic)
{
REQUIRE (minVal and maxVal);
REQUIRE (*minVal < *maxVal);
const VAL PERIOD = *maxVal - *minVal;
ENSURE (0 < PERIOD);
return (rawVal - *minVal) % PERIOD;
}
if (minVal and rawVal < *minVal)
return *minVal;
if (maxVal and rawVal > *maxVal)
return *maxVal;
// no further constraint to enforce...
return rawVal;
}
/**
* Join and combine an additional feed value with an anchor value.
* @note actual joining operation is picked based on both scales and types involved.
* @remark notably multiplicative contributions and logarithmic scales to be considered.
*/
template<typename VAL>
template<typename SRC>
inline VAL
Scale<VAL>::join (VAL const& value, SRC const& feed, Scale<SRC> const& feedScale) const
{
UNIMPLEMENTED ("join a feed with a base value, observing Scale constraints");
}
/**
* Simplified join() variant, assuming the feed is based on the same scale.
*/
template<typename VAL>
inline VAL
Scale<VAL>::join (VAL const& value, VAL const& feed) const
{
return conform (isFactor()? value * feed
: value + feed
);
}
}} // namespace lib::par
#endif /*LIB_PAR_SCALE_H*/

View file

@ -15,3 +15,13 @@ END
PLANNED "Parameter Provision" ParameterProvision_test << END
return: 0
END
PLANNED "Parameter value scales" ParameterScale_test << END
return: 0
END
PLANNED "Enumeration domains" NomSet_test << END
return: 0
END

View file

@ -0,0 +1,87 @@
/*
NomSet(Test) - verify nominal and ordinal scale enumerations
Copyright (C)
2026, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file nom-set-test.cpp
** unit test \ref NomSet_test
*/
#include "test/run.hpp"
//#include "test/test-helper.hpp"
#include "lib/par/nom-set.hpp"
#include "test/diagnostic-output.hpp"/////////////TODO
//#include <utility>
//#include <string>
//#include <vector>
//using std::string;
//using std::vector;
//using std::swap;
namespace lib {
namespace par {
namespace test{
// using lumiera::error::LUMIERA_ERROR_LOGIC;
namespace {//Test fixture....
}//(End)Test fixture
/********************************************************************************//**
* @test document the definition of domain enumerations for nominal / ordinal scales.
*/
class NomSet_test : public Test
{
virtual void
run (Arg)
{
simpleUsage();
verify_typeMarker();
}
void
simpleUsage()
{
UNIMPLEMENTED ("nebbich");
}
/** @test
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
verify_typeMarker()
{
}
};
/** Register this test class... */
LAUNCHER (NomSet_test, "unit lib");
}}} // namespace lib::par::test

View file

@ -0,0 +1,94 @@
/*
ParameterScale(Test) - verify parameter value scales
Copyright (C)
2026, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file parameter-test.cpp
** unit test \ref ParameterScale_test
*/
#include "test/run.hpp"
//#include "test/test-helper.hpp"
#include "lib/par/scale.hpp"
#include "test/diagnostic-output.hpp"/////////////TODO
//#include <utility>
//#include <string>
//#include <vector>
//using std::string;
//using std::vector;
//using std::swap;
namespace lib {
namespace par {
namespace test{
// using lumiera::error::LUMIERA_ERROR_LOGIC;
namespace {//Test fixture....
}//(End)Test fixture
/**************************************************************************//**
* @test cover properties of generic parameter containers.
*/
class ParameterScale_test : public Test
{
virtual void
run (Arg)
{
simpleUsage();
verify_Bounds();
}
void
simpleUsage()
{
Scale<int> scale = {.minVal = -5, .maxVal = 23};
CHECK (scale.isValid());
CHECK (-5 == scale.conform (-55));
CHECK (23 == scale.conform (+55));
CHECK ( 5 == scale.join (2,3) );
CHECK (-5 == scale.join (23,-55));
}
/** @test
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
verify_Bounds()
{
}
};
/** Register this test class... */
LAUNCHER (ParameterScale_test, "unit lib");
}}} // namespace lib::par::test

View file

@ -58,7 +58,10 @@ namespace test{
run (Arg)
{
simpleUsage();
verify_typeMarker();
verify_Builder();
verify_Identity();
verify_ParamType();
verify_Automation();
}
@ -79,8 +82,48 @@ namespace test{
}
/** @test explore ways to define a parameter...
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
verify_typeMarker()
verify_Builder()
{
Parameter p1 = Parameter::forValue(123.45f).build();
CHECK (123.45f == p1.getVal<float>());
p1.setVal (12u);
CHECK (12.0 == p1.getVal<double>());
Parameter p2 = Parameter::from(p1)
.maxVal (sqrt(2))
.build();
SHOW_EXPR(p2.getVal<float>());
}
/** @test
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
verify_Identity()
{
}
/** @test
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
verify_ParamType()
{
}
/** @test
* @todo WIP 9/26 🔁 define ⟶ implement
*/
void
verify_Automation()
{
}
};

File diff suppressed because it is too large Load diff