Display a linear combination: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Elixir}}: String.lstrip -> trim_leading)
(Added Sidef)
Line 309: Line 309:
-1, -2, 0, -3 ──► -e(1) - 2*e(2) - 3*e(4)
-1, -2, 0, -3 ──► -e(1) - 2*e(2) - 3*e(4)
-1 ──► -e(1)
-1 ──► -e(1)
</pre>

=={{header|Sidef}}==
{{trans|Tcl}}
<lang ruby>func linear_combination(coeffs) {
var res = ""
for e,f in (coeffs.kv) {
given(f) {
when (1) {
res += "+e(#{e+1})"
}
when (-1) {
res += "-e(#{e+1})"
}
case (.> 0) {
res += "+#{f}*e(#{e+1})"
}
case (.< 0) {
res += "#{f}*e(#{e+1})"
}
}
}
res -= /^\+/
res || 0
}

var tests = [
%n{1 2 3},
%n{0 1 2 3},
%n{1 0 3 4},
%n{1 2 0},
%n{0 0 0},
%n{0},
%n{1 1 1},
%n{-1 -1 -1},
%n{-1 -2 0 -3},
%n{-1},
]

tests.each { |t|
printf("%10s -> %-10s\n", t.join(' '), linear_combination(t))
}</lang>
{{out}}
<pre>
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)
</pre>
</pre>



Revision as of 14:57, 24 May 2017

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

<lang scheme>

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%d " plus i)) ((= a -1) (format "- e%d " i)) ((> a 0) (format "%a %d*e%d " plus a i)) ((< a 0) (format "- %d*e%d " (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 -> %a 
" linear (linear->html linear)))))

</lang>

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

Works with: Elixir version 1.3

<lang elixir>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.trim_leading("+")
   |> 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))</lang>

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

Implementation:

<lang J>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.

)</lang>

Example use:

<lang J> 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)</lang>

Perl 6

<lang perl6>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 ]

</lang>
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

<lang python> 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]]))

</lang>

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

<lang racket>#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)))

</lang>

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

<lang rexx>/*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. */</lang>

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)

Sidef

Translation of: Tcl

<lang ruby>func linear_combination(coeffs) {

   var res = ""
   for e,f in (coeffs.kv) {
       given(f) {
           when (1) {
               res += "+e(#{e+1})"
           }
           when (-1) {
               res += "-e(#{e+1})"
           }
           case (.> 0) {
               res += "+#{f}*e(#{e+1})"
           }
           case (.< 0) {
               res += "#{f}*e(#{e+1})"
           }
       }
   }
   res -= /^\+/
   res || 0

}

var tests = [

   %n{1 2 3},
   %n{0 1 2 3},
   %n{1 0 3 4},
   %n{1 2 0},
   %n{0 0 0},
   %n{0},
   %n{1 1 1},
   %n{-1 -1 -1},
   %n{-1 -2 0 -3},
   %n{-1},

]

tests.each { |t|

   printf("%10s -> %-10s\n", t.join(' '), linear_combination(t))

}</lang>

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)     

Tcl

This solution strives for legibility rather than golf.

<lang Tcl>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]]

}</lang>

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

Translation of: Perl 6

<lang zkl>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

}</lang> <lang zkl>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);</lang>

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