Доступ к коэффициентам в числовом выражении (clpr)
У меня есть несколько предложений, в которых глава представляет имена и значения набора переменных в линейном уравнении, а тело - фактическое уравнение. Вот так:
:-use_module(library(clpr)).
relation(
independents([
var(x1, X1),
var(x2, X2),
var(x3, X3)
]),
dependent(
var(y, Y)
)
):- {Y = 3 + 0.5 * X1 + 0.6 * X2 + 0.7 * X3}.
Есть ли прямой способ (косвенно) получить коэффициенты для этого уравнения? Т.е. правило, которое возвращает coefficient(VARNAME, COEFFICIENT)
например coefficient(x1, 0.5), coefficient(x2, 0.6)
и так далее.
Я знаю, что это может показаться глупым вопросом, учитывая, что было бы легко просто поместить все коэффициенты в заголовок предложения. Но в моем приложении я хочу, чтобы заголовок этих пунктов строго показывал значения каждой переменной (а не их коэффициенты). Т.е. чтобы избежать двусмысленности.
Мое текущее решение является запутанным и нелегким, вовлекающим member/2
, subtract/3
, maplist/2
и установив X1, X2, X3 в единицу или ноль, чтобы выяснить каждый наклон.
Связанный вопрос: Представление линейных функций в прологе
Спасибо!
/ JC
1 ответ
Это мое первое использование clpr
так что, если это бесполезно для вас, я признаю безумие, но мне кажется, что ключ здесь использует dump/3
преобразовать ограничение обратно в выражение Prolog, а затем обойти его, как и любую другую структуру. Поэтому я снова получаю ограничение, выполняя это:
?- relation(independents([var(x1,X1),var(x2,X2),var(x3,X3)]),
dependent(var(y,Y))),
dump([X1,X2,X3,Y],[x1,x2,x3,y], [y=Eqn]).
Eqn = 3.0+0.5*x1+0.6*x2+0.7*x3
Я думаю, что стоит помнить, как это выглядит под капотом, используя write_canonical
:
+(+(+(3.0,*(0.5,x1)),*(0.6,x2)),*(0.7,x3))
Пройдя полином, вы должны охватить всего несколько простых случаев; следующее может быть излишним:
coefficient(X=Y, Var, Coeff) :-
coefficient(X, Var, Coeff) ; coefficient(Y, Var, Coeff).
coefficient(X+Y, Var, Coeff) :-
coefficient(X, Var, Coeff) ; coefficient(Y, Var, Coeff).
coefficient(X-Y, Var, Coeff) :-
coefficient(X, Var, Coeff) ; coefficient(Y, Var, Coeff).
coefficient(X*Y, X, Y) :-
atomic(X), atomic(Y).
coefficient(X*Y, Var, Coeff) :-
coefficient(X, Var, Coeff) ; coefficient(Y, Var, Coeff).
Ваш базовый случай действительно является случаем X*Y, где они оба атомарны. Остальные пункты на самом деле просто для того, чтобы развернуть вложенность. Похоже, это делает то, что вы хотите:
?- relation(independents([var(x1,X1),var(x2,X2),var(x3,X3)]),
dependent(var(y,Y))),
dump([X1,X2,X3,Y],[x1,x2,x3,y], [y=Eqn]),
coefficient(Eqn, Var, Coeff).
Eqn = 3.0+0.5*x1+0.6*x2+0.7*x3,
Var = 0.5,
Coeff = x1,
{Y=3.0+0.5*X1+0.6*X2+0.7*X3} ;
Eqn = 3.0+0.5*x1+0.6*x2+0.7*x3,
Var = 0.6,
Coeff = x2,
{Y=3.0+0.5*X1+0.6*X2+0.7*X3} ;
Eqn = 3.0+0.5*x1+0.6*x2+0.7*x3,
Var = 0.7,
Coeff = x3,
{Y=3.0+0.5*X1+0.6*X2+0.7*X3} ;
false.
Чтобы действительно обобщить это, вы, вероятно, должны будете использовать maplist
и др. и др. преобразовать ваши списки независимых / зависимых в переменные, которые вам нужно будет передать dump/3
а затем разберитесь со случаем, когда у вас есть несколько уравнений в результате, но я не думаю, что это будет очень сложно для вас.
Надеюсь это поможет!