<commit_before># -*- coding: utf-8 -*-
"""
Helper functions to generate weak formulations using SymPy.

@author: <NAME>


This file is part of sp.fem.

sp.fem is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

sp.fem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with sp.fem.  If not, see <http://www.gnu.org/licenses/>. 
"""
import sympy as s
import numpy as np
import copy
import re

class TensorFunction(object):
    """Wrapper around SymPy for better (more concise) weak form support."""

    def __init__(self,sym='u',dim=1,tdim=1,torder=0):

        if dim>3:
            raise NotImplementedError("TensorFunction.init(): Given dimension not supported!")
        if tdim>3:
            raise NotImplementedError("TensorFunction.init(): Given target dimension not supported!")
        if torder>2:
            raise NotImplementedError("TensorFunction.init(): Given tensorial order not supported!")

        if torder>0 and tdim==1:
            tdim=dim

        self.dim=dim
        self.tdim=tdim
        self.torder=torder
        self.basic_syms=[s.symbols(x) for x in ['x','y','z']]

        def dim_eval(fun,d):
            if d==1:
                return fun(self.basic_syms[0])
            elif d==2:
                return fun(self.basic_syms[0],\
                           self.basic_syms[1])
            elif d==3:
                return fun(self.basic_syms[0],\
                           self.basic_syms[1],\
                           self.basic_syms[2])
            else:
                raise NotImplementedError("TensorFunction.init(): Given domain dimension not supported!")

        if torder==0:
            u=dim_eval(s.Function(sym),dim)
        elif torder==1:
            u={}
            for itr in range(tdim):
                u[itr]=dim_eval(s.Function(sym+str(itr+1)),dim)
        elif torder==2:
            u={}
            for itr in range(tdim):
                u[itr]={}
                for jtr in range(tdim):
                    u[itr][jtr]=dim_eval(s.Function(sym+str(itr+1)+str(jtr+1)),dim)
        else:
            raise NotImplementedError("TensorFunction.init(): Given tensor order not supported!")

        self.expr=u

    def serialize(self):
        stri=''
        if self.torder==0:
            stri=str(self.expr)
        elif self.torder==1:
            for itr in range(self.tdim):
                stri+=str(itr+1)+'. comp.: '+str(self.expr[itr])+'\n'
        elif self.torder==2:
            for itr in range(self.tdim):
                for jtr in range(self.tdim):
                    stri+='('+str(itr+1)+','+str(jtr+1)+') comp.: '+str(self.expr[itr][jtr])+'\n'
        else:
            raise NotImplementedError("TensorFunction.serialize(): Given tensor order not supported!")

        return stri

    def grad(self):
        new=copy.deepcopy(self)
        # compute gradient
        if self.torder==0:
            new.expr={}
            for itr in range(self.dim):
                new.expr[itr]=self.expr.diff(self.basic_syms[itr])
            new.torder=1
            new.tdim=self.dim
        elif self.torder==1:
            for itr in range(self.dim):
                tmp=new.expr[itr]
                new.expr[itr]={}
                for jtr in range(self.dim):
                    new.expr[itr][jtr]=tmp.diff(self.basic_syms[jtr])
                new.torder=2
        else:
            raise NotImplementedError("TensorFunction.grad(): Given tensor order not supported!")
        return new

    def div(self):
        new=copy.deepcopy(self)
        # compute divergence
        if self.torder==1:
            new.expr=0
            for itr in range(self.tdim):
                new.expr+=self.expr[itr].diff(self.basic_syms[itr])
            new.torder=0
        elif self.torder==2:
            new.expr={}
            for itr in range(self.tdim):
                new.expr[itr]=0
                for jtr in range(self.tdim):
                    new.expr[itr]+=self.expr[itr][jtr].diff(self.basic_syms[jtr])
            new.torder=1
        else:
            raise NotImplementedError("TensorFunction.div(): Given tensor order not supported!")
        return new

    def sum(self):
        new=copy.deepcopy(self)
        # sum all entries
        if self.torder==1:
            new.expr=0
            for itr in range(self.tdim):
                new.expr+=self.expr[itr]
            new.torder=0
        elif self.torder==2:
            new.expr=0
            for itr in range(self.tdim):
                for jtr in range(self.tdim):
                    new.expr+=self.expr[itr][jtr]
            new.torder=0
        else:
            raise NotImplementedError("TensorFunction.sum(): Given tensor order not supported!")
        return new

    def T(self):
        new=copy.deepcopy(self)
        if self.torder==2:
            for itr in range(self.tdim):
                for jtr in range(self.tdim):
                    new.expr[itr][jtr]=self.expr[jtr][itr]
        else:
            raise NotImplementedError("TensorFunction.T(): Transpose only supported for torder=2!")
        return new

    def __mul__(self,other):
        new=copy.deepcopy(self)
        if isinstance(other,TensorFunction):
            if self.torder!=other.torder:
                if other.torder==0:
                    other=ConstantTensor(other.expr,dim=new.dim,tdim=new.tdim,torder=new.torder)
                elif self.torder==0:
                    new=ConstantTensor(self.expr,dim=other.dim,tdim=other.tdim,torder=other.torder)
                elif self.torder==2 and other.torder==1:
                    new=ConstantTensor(0.0,dim=self.dim,tdim=self.dim,torder=1)
                    for itr in range(new.tdim):
                        for jtr in range(new.tdim):
                            new.expr[itr]+=self.expr[itr][jtr]*other.expr[jtr]
                    return new
                else:
                    raise Exception("TensorFunction.__mul__(): The given tensors not compatible (different tensorial orders and neither is scalar)!")
            if self.tdim!=other.tdim:
                raise Exception("TensorFunction.__mul__(): The given tensors not compatible (different target dims)!")

        if new.torder==0:
            if isinstance(other,TensorFunction):
                new.expr*=other.expr
            else:
                new.expr*=other
        elif new.torder==1:<commit_msg>No reason to have upperlimit for tdim in weakform module.<commit_after># -*- coding: utf-8 -*-
"""
Helper functions to generate weak formulations using SymPy.

@author: <NAME>


This file is part of sp.fem.

sp.fem is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

sp.fem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with sp.fem.  If not, see <http://www.gnu.org/licenses/>. 
"""
import sympy as s
import numpy as np
import copy
import re

class TensorFunction(object):
    """Wrapper around SymPy for better (more concise) weak form support."""

    def __init__(self,sym='u',dim=1,tdim=1,torder=0):

        if dim>3:
            raise NotImplementedError("TensorFunction.init(): Given dimension not supported!")
        if torder>2:
            raise NotImplementedError("TensorFunction.init(): Given tensorial order not supported!")

        if torder>0 and tdim==1:
            tdim=dim

        self.dim=dim
        self.tdim=tdim
        self.torder=torder
        self.basic_syms=[s.symbols(x) for x in ['x','y','z']]

        def dim_eval(fun,d):
            if d==1:
                return fun(self.basic_syms[0])
            elif d==2:
                return fun(self.basic_syms[0],\
                           self.basic_syms[1])
            elif d==3:
                return fun(self.basic_syms[0],\
                           self.basic_syms[1],\
                           self.basic_syms[2])
            else:
                raise NotImplementedError("TensorFunction.init(): Given domain dimension not supported!")

        if torder==0:
            u=dim_eval(s.Function(sym),dim)
        elif torder==1:
            u={}
            for itr in range(tdim):
                u[itr]=dim_eval(s.Function(sym+str(itr+1)),dim)
        elif torder==2:
            u={}
            for itr in range(tdim):
                u[itr]={}
                for jtr in range(tdim):
                    u[itr][jtr]=dim_eval(s.Function(sym+str(itr+1)+str(jtr+1)),dim)
        else:
            raise NotImplementedError("TensorFunction.init(): Given tensor order not supported!")

        self.expr=u

    def serialize(self):
        stri=''
        if self.torder==0:
            stri=str(self.expr)
        elif self.torder==1:
            for itr in range(self.tdim):
                stri+=str(itr+1)+'. comp.: '+str(self.expr[itr])+'\n'
        elif self.torder==2:
            for itr in range(self.tdim):
                for jtr in range(self.tdim):
                    stri+='('+str(itr+1)+','+str(jtr+1)+') comp.: '+str(self.expr[itr][jtr])+'\n'
        else:
            raise NotImplementedError("TensorFunction.serialize(): Given tensor order not supported!")

        return stri

    def grad(self):
        new=copy.deepcopy(self)
        # compute gradient
        if self.torder==0:
            new.expr={}
            for itr in range(self.dim):
                new.expr[itr]=self.expr.diff(self.basic_syms[itr])
            new.torder=1
            new.tdim=self.dim
        elif self.torder==1:
            for itr in range(self.dim):
                tmp=new.expr[itr]
                new.expr[itr]={}
                for jtr in range(self.dim):
                    new.expr[itr][jtr]=tmp.diff(self.basic_syms[jtr])
                new.torder=2
        else:
            raise NotImplementedError("TensorFunction.grad(): Given tensor order not supported!")
        return new

    def div(self):
        new=copy.deepcopy(self)
        # compute divergence
        if self.torder==1:
            new.expr=0
            for itr in range(self.tdim):
                new.expr+=self.expr[itr].diff(self.basic_syms[itr])
            new.torder=0
        elif self.torder==2:
            new.expr={}
            for itr in range(self.tdim):
                new.expr[itr]=0
                for jtr in range(self.tdim):
                    new.expr[itr]+=self.expr[itr][jtr].diff(self.basic_syms[jtr])
            new.torder=1
        else:
            raise NotImplementedError("TensorFunction.div(): Given tensor order not supported!")
        return new

    def sum(self):
        new=copy.deepcopy(self)
        # sum all entries
        if self.torder==1:
            new.expr=0
            for itr in range(self.tdim):
                new.expr+=self.expr[itr]
            new.torder=0
        elif self.torder==2:
            new.expr=0
            for itr in range(self.tdim):
                for jtr in range(self.tdim):
                    new.expr+=self.expr[itr][jtr]
            new.torder=0
        else:
            raise NotImplementedError("TensorFunction.sum(): Given tensor order not supported!")
        return new

    def T(self):
        new=copy.deepcopy(self)
        if self.torder==2:
            for itr in range(self.tdim):
                for jtr in range(self.tdim):
                    new.expr[itr][jtr]=self.expr[jtr][itr]
        else:
            raise NotImplementedError("TensorFunction.T(): Transpose only supported for torder=2!")
        return new

    def __mul__(self,other):
        new=copy.deepcopy(self)
        if isinstance(other,TensorFunction):
            if self.torder!=other.torder:
                if other.torder==0:
                    other=ConstantTensor(other.expr,dim=new.dim,tdim=new.tdim,torder=new.torder)
                elif self.torder==0:
                    new=ConstantTensor(self.expr,dim=other.dim,tdim=other.tdim,torder=other.torder)
                elif self.torder==2 and other.torder==1:
                    new=ConstantTensor(0.0,dim=self.dim,tdim=self.tdim,torder=1)
                    for itr in range(new.tdim):
                        for jtr in range(new.tdim):
                            new.expr[itr]+=self.expr[itr][jtr]*other.expr[jtr]
                    return new
                else:
                    raise Exception("TensorFunction.__mul__(): The given tensors not compatible (different tensorial orders and neither is scalar)!")
            if self.tdim!=other.tdim:
                raise Exception("TensorFunction.__mul__(): The given tensors not compatible (different target dims)!")

        if new.torder==0:
            if isinstance(other,TensorFunction):
                new.expr*=other.expr
            else:
                new.expr*=other
        elif new.torder==1:
{'fraction_non_alphanumeric': 0.11339140705743393, 'fraction_numerical': 0.008489591023180275, 'mean_word_length': 1.8287742743787847, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5851608', 'n_tokens_mistral': 4048, 'n_tokens_neox': 3957, 'n_words': 965}