Dimensional constraints don't seem to be applied #423
-
What happened?Hi! I'm experimenting with dimensional constraints and finding non-expected behaviour. When initializing the model I set "dimensional_constraint_penalty=10**5" and "select_k_features=8". The first 2 equations found by the model have, as expected, a 10000 penalty to the loss, and they have the wrong units ([nm] and [nm]+[J / V ^ 2]. The next equation is a constant and does not have the 10000 penalty loss. All following equations also do not have the 10000 penalty loss even though they are not in units J / V (which in SI units should be A*s). The same is happening when setting the units to be J / V ^ 2 for instance. Is this the expected behaviour, or am I missing something? The function chosen, with a loss of 0.8, is not dimensionally consistent with itself, and is not even close to J/V. Thank you Version0.16.3 Operating SystemWindows Package Managerpip InterfaceJupyter Notebook Relevant log outputNo response Extra InfoThis is what I'm using to run, the data here is random, just so it could be run, in my actual code I'm using real data.
|
Beta Was this translation helpful? Give feedback.
Replies: 9 comments 7 replies
This comment has been hidden.
This comment has been hidden.
-
Also, I would consider lowering the |
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
Actually maybe I misunderstood the problem. It could already be working but maybe the output is unclear. Could you describe:
what you mean here with an example? Note that any constants found during the search actually have their own units. The string |
Beta Was this translation helpful? Give feedback.
-
Thanks for the tip, I will try it, I had put it to such high value because it is the one suggested in the example of dimensional, but I guess in that case it was so high because the values were also very high.
I was thinking about exactly that, that maybe this was not a bug, but just a misunderstanding from my part about the functionality. From what I gathered, there is no way to get the individual units of each constant term, which could be important. About your suggestion, the removal of the wildcard, or at least a way to distinguish between unitless constants and constants with units (by having them have a chosen complexity for instance), would be very applicable. Maybe I'm misunderstanding the algorithm backstage, but if you can have any constant be any unit then it seems that it will most likely bypass the unit search (maybe in my case it was more pressing, because some of my variables were indeed constants). This means that clearly this was not a bug, but just a misunderstanding of my part. |
Beta Was this translation helpful? Give feedback.
-
Right, as an example, the expression: "y[m s⁻² kg] = (M[kg] * 2.6353e-22[⋅])" is actually dimensionally consistent, because the However, the expression: "y[m s⁻² kg] = (M[kg] * 2.6353e-22[⋅] + m[kg])" would not be dimensionally consistent, because there does not exist any such units inserted into the So, you may be asking: why not show units in the Since we need to very rapidly evaluate dimensional consistency, the tradeoff just did not seem worth it, compared to the user figuring out the units afterwards. But maybe there is a fast way to do it, and we could display the units instead of You can see the dimensional analysis code here: For example, the code for addition and subtraction operators is given here ( @eval function $(op)(l::W, r::W) where {Q,W<:WildcardQuantity{Q}}
l.violates && return l
r.violates && return r
if same_dimensions(l, r)
return W($(op)(l.val, r.val), l.wildcard && r.wildcard, false)
elseif l.wildcard && r.wildcard
return W(
constructor_of(Q)($(op)(ustrip(l), ustrip(r)), typeof(dimension(l))),
true,
false,
)
elseif l.wildcard
return W($(op)(constructor_of(Q)(ustrip(l), dimension(r)), r.val), false, false)
elseif r.wildcard
return W($(op)(l.val, constructor_of(Q)(ustrip(r), dimension(l))), false, false)
else
return W(one(Q), false, true)
end
end You can see there are five branches (after first checking if either the left or right argument is already dimensionally invalid):
|
Beta Was this translation helpful? Give feedback.
-
The type used for "wildcard" quantities is this one: """
WildcardQuantity{Q<:AbstractQuantity}
A wrapper for a `AbstractQuantity` that allows for a wildcard feature, indicating
there is a free constant whose dimensions are not yet determined.
Also stores a flag indicating whether an expression is dimensionally consistent.
"""
struct WildcardQuantity{Q<:AbstractQuantity}
val::Q
wildcard::Bool
violates::Bool
end
|
Beta Was this translation helpful? Give feedback.
-
Also, as a quick and dirty way to avoid learned constants, you can use |
Beta Was this translation helpful? Give feedback.
-
(Moved to discussion as this seems to be not a bug. Let me know if otherwise and I can move it back!) |
Beta Was this translation helpful? Give feedback.
@SrGonao btw, it should be pretty easy to turn off the "wildcard unit" functionality, so that all learned constants are dimensionless. We just need to add a boolean parameter to the
Options
struct in SymbolicRegression.jl. That parameter would just end up here:https://github.com/MilesCranmer/SymbolicRegression.jl/blob/5c95478d8a01f2c6b6b54da26615c07fb6d3aee1/src/DimensionalAnalysis.jl#L121
It would set that
true
tofalse
if the user chooses to disable the wildcard units. That's literally all that's needed. Now I just need to find some time to add it...