Display a linear combination

From Rosetta Code
Display a linear combination is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Task

Display a finite linear combination in an infinite vector basis .

Write a function that, when given a finite list of scalars ,
creates a string representing the linear combination in an explicit format often used in mathematics, that is:

where



The output must comply to the following rules:

  •   don't show null terms, unless the whole combination is null.
e(1)     is fine,     e(1) + 0*e(3)     or     e(1) + 0     is wrong.
  •   don't show scalars when they are equal to one or minus one.
e(3)     is fine,     1*e(3)     is wrong.
  •   don't prefix by a minus sign if it follows a preceding term.   Instead you use subtraction.
e(4) - e(5)     is fine,     e(4) + -e(5)     is wrong.


Show here output for the following lists of scalars:

 1)    1,  2,  3
 2)    0,  1,  2,  3
 3)    1,  0,  3,  4
 4)    1,  2,  0
 5)    0,  0,  0
 6)    0
 7)    1,  1,  1
 8)   -1, -1, -1
 9)   -1, -2,  0, -3
10)   -1



EchoLisp[edit]

 
;; build an html string from list of coeffs
 
(define (linear->html coeffs)
(define plus #f)
(or*
(for/fold (html "") ((a coeffs) (i (in-naturals 1)))
(unless (zero? a)
(set! plus (if plus "+" "")))
(string-append html
(cond
((= a 1) (format "%a e<sub>%d</sub> " plus i))
((= a -1) (format "- e<sub>%d</sub> " i))
((> a 0) (format "%a %d*e<sub>%d</sub> " plus a i))
((< a 0) (format "- %d*e<sub>%d</sub> " (abs a) i))
(else ""))))
"0"))
 
(define linears '((1 2 3)
(0 1 2 3)
(1 0 3 4)
(1 2 0)
(0 0 0)
(0)
(1 1 1)
(-1 -1 -1)
(-1 -2 0 -3)
(-1)))
 
(define (task linears)
(html-print ;; send string to stdout
(for/string ((linear linears))
(format "%a -> <span style='color:blue'>%a</span> <br>" linear (linear->html linear)))))
 
Output:

(1 2 3) -> e1 + 2*e2 + 3*e3
(0 1 2 3) -> e2 + 2*e3 + 3*e4
(1 0 3 4) -> e1 + 3*e3 + 4*e4
(1 2 0) -> e1 + 2*e2
(0 0 0) -> 0
(0) -> 0
(1 1 1) -> e1 + e2 + e3
(-1 -1 -1) -> - e1 - e2 - e3
(-1 -2 0 -3) -> - e1 - 2*e2 - 3*e4
(-1) -> - e1

Elixir[edit]

defmodule Linear_combination do
def display(coeff) do
Enum.with_index(coeff)
|> Enum.map_join(fn {n,i} ->
{m,s} = if n<0, do: {-n,"-"}, else: {n,"+"}
case {m,i} do
{0,_} -> ""
{1,i} -> "#{s}e(#{i+1})"
{n,i} -> "#{s}#{n}*e(#{i+1})"
end
end)
|> String.lstrip(?+)
|> case do
"" -> IO.puts "0"
str -> IO.puts str
end
end
end
 
coeffs =
[ [1, 2, 3],
[0, 1, 2, 3],
[1, 0, 3, 4],
[1, 2, 0],
[0, 0, 0],
[0],
[1, 1, 1],
[-1, -1, -1],
[-1, -2, 0, -3],
[-1]
]
Enum.each(coeffs, &Linear_combination.display(&1))
Output:
e(1)+2*e(2)+3*e(3)
e(2)+2*e(3)+3*e(4)
e(1)+3*e(3)+4*e(4)
e(1)+2*e(2)
0
0
e(1)+e(2)+e(3)
-e(1)-e(2)-e(3)
-e(1)-2*e(2)-3*e(4)
-e(1)

J[edit]

Implementation:

fourbanger=:3 :0
e=. ('e(',')',~])@":&.> 1+i.#y
firstpos=. 0< {.y-.0
if. */0=y do. '0' else. firstpos}.;y gluedto e end.
)
 
gluedto=:4 :0 each
pfx=. '+-' {~ x<0
select. |x
case. 0 do. ''
case. 1 do. pfx,y
case. do. pfx,(":|x),'*',y
end.
)

Example use:

   fourbanger 1 2 3
e(1)+2*e(2)+3*e(3)
fourbanger 0 1 2 3
e(2)+2*e(3)+3*e(4)
fourbanger 1 0 3 4
e(1)+3*e(3)+4*e(4)
fourbanger 0 0 0
0
fourbanger 0
0
fourbanger 1 1 1
e(1)+e(2)+e(3)
fourbanger _1 _1 _1
-e(1)-e(2)-e(3)
fourbanger _1 _2 0 _3
-e(1)-2*e(2)-3*e(4)
fourbanger _1
-e(1)

Perl 6[edit]

sub linear-combination(@coeff) {
(@coeff Z=> map { "e($_)" }, 1 .. *)
.grep(+*.key)
.map({ .key ~ '*' ~ .value })
.join(' + ')
.subst('+ -', '- ', :g)
.subst(/<|w>1\*/, '', :g)
|| '0'
}
 
say linear-combination($_) for
[1, 2, 3],
[0, 1, 2, 3],
[1, 0, 3, 4],
[1, 2, 0],
[0, 0, 0],
[0],
[1, 1, 1],
[-1, -1, -1],
[-1, -2, 0, -3],
[-1 ]
;
Output:
e(1) + 2*e(2) + 3*e(3)
e(2) + 2*e(3) + 3*e(4)
e(1) + 3*e(3) + 4*e(4)
e(1) + 2*e(2)
0
0
e(1) + e(2) + e(3)
-e(1) - e(2) - e(3)
-e(1) - 2*e(2) - 3*e(4)
-e(1)

Python[edit]

 
def linear(x):
return ' + '.join(['{}e({})'.format('-' if v == -1 else '' if v == 1 else str(v) + '*', i + 1)
for i, v in enumerate(x) if v] or ['0']).replace(' + -', ' - ')
 
list(map(lambda x: print(linear(x)), [[1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0],
[0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, 3], [-1]]))
 
Output:
e(1) + 2*e(2) + 3*e(3)
e(2) + 2*e(3) + 3*e(4)
e(1) + 3*e(3) + 4*e(4)
e(1) + 2*e(2)
0
0
e(1) + e(2) + e(3)
-e(1) - e(2) - e(3)
-e(1) - 2*e(2) + 3*e(4)
-e(1)

Racket[edit]

#lang racket/base
(require racket/match racket/string)
 
(define (linear-combination->string es)
(let inr ((es es) (i 1) (rv ""))
(match* (es rv)
[((list) "") "0"]
[((list) rv) rv]
[((list (? zero?) t ...) rv)
(inr t (add1 i) rv)]
[((list n t ...) rv)
(define ±n
(match* (n rv)
 ;; zero is handled above
[(1 "") ""]
[(1 _) "+"]
[(-1 _) "-"]
[((? positive? n) (not "")) (format "+~a*" n)]
[(n _) (format "~a*" n)]))
(inr t (add1 i) (string-append rv ±n "e("(number->string i)")"))])))
 
(for-each
(compose displayln linear-combination->string)
'((1 2 3)
(0 1 2 3)
(1 0 3 4)
(1 2 0)
(0 0 0)
(0)
(1 1 1)
(-1 -1 -1)
(-1 -2 0 -3)
(-1)))
 
Output:
e(1)+2*e(2)+3*e(3)
e(2)+2*e(3)+3*e(4)
e(1)+3*e(3)+4*e(4)
e(1)+2*e(2)
0
0
e(1)+e(2)+e(3)
-e(1)-e(2)-e(3)
-e(1)-2*e(2)-3*e(4)
-e(1)

REXX[edit]

/*REXX program displays a  finite liner combination  in an  infinite vector basis.      */
@.=.; @.1 = '1, 2, 3'
@.2 = '0, 1, 2, 3'
@.3 = '1, 0, 3, 4'
@.4 = '1, 2, 0'
@.5 = '0, 0, 0'
@.6 = 0
@.7 = '1, 1, 1'
@.8 = '-1, -1, -1'
@.9 = '-1, -2, 0, -3'
@.10 = -1
do j=1 while @.j\==.; n=0 /*process each vector; zero element cnt*/
y=space( translate(@.j, ,',') ) /*elide commas and superfluous blanks. */
$= /*nullify output (liner combination).*/
do k=1 for words(y); #=word(y, k) /* ◄───── process each of the elements.*/
if #=0 then iterate; a=abs(# / 1) /*if the value is zero, then ignore it.*/
s='+ '; if #<0 then s='- ' /*define the sign: plus(+) or minus(-)*/
n=n+1; if n==1 then s=strip(s) /*if the 1st element used, remove plus.*/
if a\==1 then s=s || a'*' /*if multiplier is unity, then ignore #*/
$=$ s'e('k")" /*construct a liner combination element*/
end /*k*/
 
$=strip( strip($), 'L', "+") /*strip leading plus sign (1st element)*/
if $=='' then $=0 /*handle special case of no elements. */
say right( space(@.j), 20) ' ──► ' strip($) /*align the output for presentation. */
end /*j*/
/*stick a fork in it, we're all done. */

output   when using the default inputs:

             1, 2, 3  ──►  e(1) + 2*e(2) + 3*e(3)
          0, 1, 2, 3  ──►  e(2) + 2*e(3) + 3*e(4)
          1, 0, 3, 4  ──►  e(1) + 3*e(3) + 4*e(4)
             1, 2, 0  ──►  e(1) + 2*e(2)
             0, 0, 0  ──►  0
                   0  ──►  0
             1, 1, 1  ──►  e(1) + e(2) + e(3)
          -1, -1, -1  ──►  -e(1) - e(2) - e(3)
       -1, -2, 0, -3  ──►  -e(1) - 2*e(2) - 3*e(4)
                  -1  ──►  -e(1)

Tcl[edit]

This solution strives for legibility rather than golf.

proc lincom {factors} {
set exp 0
set res ""
foreach f $factors {
incr exp
if {$f == 0} {
continue
} elseif {$f == 1} {
append res "+e($exp)"
} elseif {$f == -1} {
append res "-e($exp)"
} elseif {$f > 0} {
append res "+$f*e($exp)"
} else {
append res "$f*e($exp)"
}
}
if {$res eq ""} {set res 0}
regsub {^\+} $res {} res
return $res
}
 
foreach test {
{1 2 3}
{0 1 2 3}
{1 0 3 4}
{1 2 0}
{0 0 0}
{0}
{1 1 1}
{-1 -1 -1}
{-1 -2 0 -3}
{-1}
} {
puts [format "%10s -> %-10s" $test [lincom $test]]
}
Output:
     1 2 3 -> e(1)+2*e(2)+3*e(3)
   0 1 2 3 -> e(2)+2*e(3)+3*e(4)
   1 0 3 4 -> e(1)+3*e(3)+4*e(4)
     1 2 0 -> e(1)+2*e(2)
     0 0 0 -> 0         
         0 -> 0         
     1 1 1 -> e(1)+e(2)+e(3)
  -1 -1 -1 -> -e(1)-e(2)-e(3)
-1 -2 0 -3 -> -e(1)-2*e(2)-3*e(4)
        -1 -> -e(1)     

zkl[edit]

Translation of: Perl 6
fcn linearCombination(coeffs){
[1..].zipWith(fcn(n,c){ if(c==0) "" else "%s*e(%s)".fmt(c,n) },coeffs)
.filter().concat("+").replace("+-","-").replace("1*","")
or 0
}
T(T(1,2,3),T(0,1,2,3),T(1,0,3,4),T(1,2,0),T(0,0,0),T(0),T(1,1,1),T(-1,-1,-1),
T(-1,-2,0,-3),T(-1),T)
.pump(Console.println,linearCombination);
Output:
e(1)+2*e(2)+3*e(3)
e(2)+2*e(3)+3*e(4)
e(1)+3*e(3)+4*e(4)
e(1)+2*e(2)
0
0
e(1)+e(2)+e(3)
-e(1)-e(2)-e(3)
-e(1)-2*e(2)-3*e(4)
-e(1)
0