Доступ к коэффициентам в числовом выражении (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 а затем разберитесь со случаем, когда у вас есть несколько уравнений в результате, но я не думаю, что это будет очень сложно для вас.

Надеюсь это поможет!

Другие вопросы по тегам